使用递归

时间:2016-01-07 00:24:32

标签: java eclipse recursion

我的任务是创建一个递归方法makeDecimal,当传递一个数字(由String表示)及其基数时,将该数字转换为基数10.您将需要使用方法Integer.parseInt(str)。 (提示:使用子字符串。)此方法采用String并返回其整数形式。

例如,Integer.parseInt("21");将返回int 21。

以下是makeDecimal如何工作的一些示例:

makeDecimal("11", 2)将返回3.

makeDecimal("100", 4)将返回16。

这是我的尝试:

public static double makeDecimal(String number, int base){
    int len = number.length();
    double f = 0;

    if(len <= 0)
        return 0;
    else{
        makeDecimal(number,base);

        double temp = Integer.parseInt(number.substring(len - 1, len + 1));
        f = f + temp * Math.pow(3, len-1);
    }

    len--;
    return f;
}

但是,我收到“溢出错误”,我不知道它是否写得正确。

4 个答案:

答案 0 :(得分:7)

您正在使用与传入的完全相同的参数进行递归。因此,调用本身会以相同的方式递归,直到堆栈溢出。这不是递归应该如何工作的。相反,您需要弄清楚如何在当前调用中执行一个问题,然后递归以执行较小的问题。

在您的代码中,它甚至不清楚您使用的是什么逻辑。 (计算3 len - 1 的重点是什么?)试试这个:

  • 如果输入字符串的长度为0,则答案为0(您正确的那部分)
  • 否则,取最后一位数字并在当前基数中解析它。然后答案是值加base倍于的所有值,但不包括输入的最后一位数。 (提示:这是一个使用递归的好地方。)

您应该能够将该描述转换为适当的方法调用并使用substring()

哦,另外一件事:这里没有理由使用double值。只需坚持int变量。你不会需要Math.pow()

答案 1 :(得分:3)

这是使用递归substringInteger.parseInt的最简单的解决方案:

public int makeDecimal(String value, int base) {
    // exit from recursion
    if (value.length() < 1) 
        return 0;

    //parsing last character of string
    int charValue = Integer.parseInt(value.substring(value.length() - 1), base);

    //calling recursion for string without last character
    return makeDecimal(value.substring(0, value.length() - 1), base) * base + charValue;
} 

答案 2 :(得分:1)

编辑:起初我曾经说过,这个解决方案的递归是有义务的,所以我没有它的原始答案可以在下面四个。

以下是递归的解决方案,没有substringMath.pow

public double makeDecimal(String value, int base) {
    makeDecimal(value, base, value.length() - 1);
}

public double makeDecimal(String value, int base, int index) {
    double result = 0;

    if (index < 0)
        return result;

    double charValue = 0;
    char currentChar =  values.get(Character.toUpperCase(value.charAt(index));
    if (currentChar >= 0 && currentChar <= '9') {
       charValue = currentChar - '0';
    } else if (currentChar >= 'A' && currentChar <= 'Z') {
        charValue = currentChar - 'A';
    } else {
        throw new InvalidValueException("Unsupported character '" + currentChar + "'.");
    }

    if (charValue >= base) {
        throw new InvalidValueException("Wrong character '" + currentChar + "' for base '" base + "'.");
    }

    return makeDecimal(value, base, index - 1)) * base + charValue;
} 

原始答案:这样的事情适用于从2到36岁的任何基地:

private Map<Character, Integer> getCharValues(int base)
{
    Map<Character, Integer> values = new HashMap<Character, Integer>();
    for (int i = 0; i < base; i++){
        if (i < 10) {
            values.put('0' + i, i);
        } else if (i < 36) {
            values.put('A' + i - 10, i);
        } else {
            throw new InvalidValueException("Base '" + base + "' not supported");
        }
    }
    return values;
}

public double makeDecimal(String value, int base)
{
    Map<Character, Integer> charValues = getCharValues(base);
    double result = 0;
    for (int i = 0; i < value.length(); i++){
        result = result * base + charValues.get(Character.toUpperCase(Character.toUpperCase(value.charAt(i))));
    }
    return result;
}

如果你需要超过36的基数,你可以扩展方法getCharValues中的字符集。另外,最好不要每次创建HasMap,只是将它存储为最大基数,如果char值超过给定的基数则抛出异常。

答案 3 :(得分:1)

这是我用Python编写原型后的解决方案(如果您有兴趣,我也可以包含Python源代码):

import java.util.HashMap;
import java.util.Map;

public class MakeDecimal {

    public static final Map<Character, Integer> alphabet = buildAlphabetTable();

    public static void main(String[] args) {

        // System.out.println(alphabet);
        System.out.println(makeDecimal("af10bb1", 16));
    }

    // pos refers to the position of the character in the string.
    // For example, if you have the following binary string 100
    // then 1 at the left is at position 2, 
    // the 0 in the middle is at position 1,
    // and the right most 0 is at position 0 
    // (you start counting from the right side).
    // In general, you would convert that string in the following way:
    // 2^2 * 1 + 2^1 * 0 + 2^0 * 0 = 4

    // If the base was n, then you would have
    // first * n^{pos + "length of string - 1"} + ... + penultimate * n^{pos + 1} + last * n^{pos}
    // Note that pos starts from 0.
    private static int makeDecimal(String s, int base, int pos) {
        if (s.length() == 0) {
            return 0;
        } else {
            int last = (int) Math.pow(base, pos) * alphabet.get(s.charAt(s.length() - 1));
            return makeDecimal(s.substring(0, s.length() - 1), base, pos + 1) + last;
        }
    }

    public static int makeDecimal(String s, int base) {
        if (s.length() == 0) {
            return 0;
        }

        if (base < 2 || base > 36) {
            throw new IllegalArgumentException("not base >= 2 and base <= 36");
        }

        return makeDecimal(s.toLowerCase(), base, 0);
    }


    // Creates a table that maps characters to their decimal value
    // the characters can be also '0' or '2' (or any other character number)
    // or they can be a character of the English alphabet
    private static Map<Character, Integer> buildAlphabetTable() {
        Map<Character, Integer> a = new HashMap<>(36);

        int i = 0;

        for (char c = '0'; c <= '9'; c++, i++) {
            a.put(c, i);
        }

        for (char c = 'a'; c <= 'z'; c++, i++) {
            a.put(c, i);
        }

        return a;
    }

}

我的解决方案基于以下帖子,您应该阅读以便更新如何在基数之间进行转换的想法。

  

http://www.purplemath.com/modules/numbbase.htm

它不接受小于2或大于36的基数。当你以大写字母传递英文字符时它也会处理。