使用java中的递归方法进行记忆

时间:2014-02-22 08:09:13

标签: java recursion memoization collatz

我正在做家庭作业,我已经筋疲力尽了。我是编程新手,这是我的第一个编程课。

这就是问题:

考虑Collat​​z.java中的以下递归函数,它与数论中一个着名的未解决问题有关,称为Collat​​z问题或3n + 1问题。

public static void collatz(int n) {
StdOut.print(n + " ");
if (n == 1) return;
if (n % 2 == 0) collatz(n / 2);
else            collatz(3*n + 1);}

例如,调用collat​​z(7)会打印序列 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 作为17个递归调用的结果。编写一个采用命令行参数N的程序,并返回n< N为collat​​z(n)的递归调用次数最大化的N.提示:使用memoization。未解决的问题是没有人知道函数是否终止n的所有正值(数学归纳没有帮助,因为其中一个递归调用是参数的较大值)。

我尝试了几件事:使用for循环,尝试计算每次执行方法时变量递增的执行次数,以及数小时的苦差事。

显然,我应该以某种方式使用数组来进行记忆。但是,我不明白在启动时必须指定数组的长度时如何使用数组。

我做错了吗?我误解了这个问题吗?

到目前为止,这是我的代码。它反映了尝试创建整数数组的尝试:

public class Collatz2 {
public static int collatz2(int n)
{

    StdOut.print(n + " ");
    if (n==1) {return 1;}
    else if (n==2) {return 1;}
    else if (n%2==0) {return collatz2(n/2);}
    else {return collatz2(3*n+1);}

}



public static void main(String[] args)
{
    int N = Integer.parseInt(args[0]);
    StdOut.println(collatz2(N));

}
}

编辑:

我写了一个单独的程序

public class Count {
   public static void main(String[] args) { 
        int count = 0;       

        while (!StdIn.isEmpty()) {
            int value = StdIn.readInt();
            count++;
        }

        StdOut.println("count is " + count);
    }
}

然后我使用了管道:%java Collat​​z2 6 | java Count

它运作得很好。

2 个答案:

答案 0 :(得分:4)

由于您对最大序列大小感兴趣而不一定对序列本身感兴趣,因此最好让collat​​z返回序列的大小。

private static final Map<Integer,Integer> previousResults = new HashMap<>();

private static int collatz(int n) {
    int result = 1;
    if(previousResults.containsKey(n)) {
        return previousResults.get(n);
    } else {
        if(n==1) result = 1;
        else if(n%2==0) result += collatz(n/2);
        else result += collatz(3*n + 1);
        previousResults.put(n, result);
        return result;
    }
}

通过在Map previousResults中存储n的先前值的序列大小来实现memoization。

您可以在主函数中查找最大值:

public static void main(String[] args) {
    int N = Integer.parseInt(args[0]);
    int maxn=0, maxSize=0;
    for(int n=N; n>0; n--) {
        int size = collatz(n);
        if(size>maxSize) {
            maxn = n;
            maxSize = size;
        }
    }
    System.out.println(maxn + " - " + maxSize);
}

答案 1 :(得分:1)

这里的技巧是编写一个递归方法,其中参数是你想要“memoize”的值。例如,这是一个方法的版本,它将返回达到1所需的步骤数(当然,假设n大于或等于1):

public int countSteps(final int n)
{
    return doCollatz(0, n);
}

public static int doCollatz(final int nrSteps, final int n)
{
    if (n == 1)
        return nrSteps;

    final int next = n % 2 == 0 ? n / 2 : 3 * n + 1;
    return doCollatz(nrSteps + 1, next);
}

如果您要记录不同的步骤,则会在您通过时将List<Integer>作为参数传递给.add()等等。