简体   繁体   English

用java中的递归方法记忆

[英]Memoization with recursive method in java

I am working on a homework assignment, and I have completely exhausted myself.我正在做家庭作业,我已经筋疲力尽了。 I'm new to programming, and this is my first programming class.我是编程新手,这是我的第一堂编程课。

this is the problem:这就是问题:

Consider the following recursive function in Collatz.java, which is related to a famous unsolved problem in number theory, known as the Collatz problem or the 3n + 1 problem.考虑 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);}

For example, a call to collatz(7) prints the sequence 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 as a consequence of 17 recursive calls.例如,调用 collat​​z(7) 会打印序列 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 作为 17 次递归调用的结果。 Write a program that takes a command-line argument N and returns the value of n < N for which the number of recursive calls for collatz(n) is maximized.编写一个程序,接受命令行参数 N 并返回 n < N 的值,此时 collat​​z(n) 的递归调用次数最大化。 Hint: use memoization.提示:使用记忆。 The unsolved problem is that no one knows whether the function terminates for all positive values of n (mathematical induction is no help because one of the recursive calls is for a larger value of the argument).未解决的问题是没有人知道函数是否对 n 的所有正值终止(数学归纳法没有帮助,因为递归调用之一是针对更大的参数值)。

I have tried several things: using a for loop, trying to count the number of executions with a variable incremented each time the method executed, and hours of drudgery.我尝试了几件事:使用 for 循环,尝试使用每次执行方法时递增的变量来计算执行次数,以及繁重的工作时间。

Apparently, I'm supposed to use an array somehow with the memoization.显然,我应该在记忆中以某种方式使用数组。 However, I don't understand how I could use an array when an array's length must be specified upon initiation.但是,当必须在启动时指定数组的长度时,我不明白如何使用数组。

Am I doing something completely wrong?我做错了什么吗? Am I misreading the question?我误读了这个问题吗?

Here is my code so far.到目前为止,这是我的代码。 It reflects an attempt at trying to create an integer array:它反映了尝试创建整数数组的尝试:

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));

}
}

EDIT:编辑:

I wrote a separate program我写了一个单独的程序

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);
    }
}

I then used piping: %java Collatz2 6 |然后我使用了管道:%java Collat​​z2 6 | java Count计数

and it worked just fine.它工作得很好。

Since you are interested in the maximum sequence size and not necessarily the sequence itself, it is better to have collatz return the size of the sequence.由于您对最大序列大小而不一定是序列本身感兴趣,因此最好让 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;
    }
}

The memoization is implemented by storing sequence sizes for previous values of n in Map previousResults.记忆是通过在 Map previousResults 中存储之前 n 值的序列大小来实现的。

You can look for the maximum in the main function:您可以在 main 函数中查找最大值:

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);
}

The trick here is to write a recursive method where an argument is the value you want to "memoize".这里的技巧是编写一个递归方法,其中参数是您想要“记忆”的值。 For instance, here is a version of a method which will return the number of steps needed to reach 1 (it supposes that n is greater than or equal to 1, of course):例如,这里有一个方法版本,它将返回达到 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);
}

If you were to record the different steps instead, you'd pass a List<Integer> as an argument and .add() to it as you went through, etc etc.如果你要记录不同的步骤,你会传递一个List<Integer>作为参数和.add()在你经历时传递给它,等等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM