您好我正在项目Euler中处理Collatz序列问题(问题14)。我的代码适用于低于100000的数字,但是数字越大,我的堆栈溢出错误。
有没有办法可以重新设计代码以使用尾递归,或者防止堆栈溢出。代码如下:
import java.util.*;
public class v4
{
// use a HashMap to store computed number, and chain size
static HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
public static void main(String[] args)
{
hm.put(1, 1);
final int CEILING_MAX=Integer.parseInt(args[0]);
int len=1;
int max_count=1;
int max_seed=1;
for(int i=2; i<CEILING_MAX; i++)
{
len = seqCount(i);
if(len > max_count)
{
max_count = len;
max_seed = i;
}
}
System.out.println(max_seed+"\t"+max_count);
}
// find the size of the hailstone sequence for N
public static int seqCount(int n)
{
if(hm.get(n) != null)
{
return hm.get(n);
}
if(n ==1)
{
return 1;
}
else
{
int length = 1 + seqCount(nextSeq(n));
hm.put(n, length);
return length;
}
}
// Find the next element in the sequence
public static int nextSeq(int n)
{
if(n%2 == 0)
{
return n/2;
}
else
{
return n*3+1;
}
}
}
答案 0 :(得分:8)
您的问题不在于堆栈的大小(您已经记住了值),但是
提示:
public static int seqCount(int n)
{
if(hm.get(n) != null) {
return hm.get(n);
}
if (n < 1) {
// this should never happen, right? ;)
} ...
...
希望这足够了:)。
P.S。你会在很多项目的欧拉问题中遇到对BigNums的需求......
答案 1 :(得分:2)
如果您从整数更改为长,它将为您提供足够的空间来解决问题。 以下是我用来回答这个问题的代码:
for(int i=1;i<=1000000;i+=2)
{
steps=1;
int n=i;
long current=i;
while(current!=1)
{
if(current%2==0)
{
current=current/2;
}else{
current=(current*3)+1;
}
steps++;
}
if(steps>best)
{
best=steps;
answer=n;
}
}
强行执行,大约需要9秒才能运行
答案 2 :(得分:1)
旁注(因为看起来你实际上并不需要针对这个问题进行尾调用优化):Java中没有尾调用优化,据我所知,JVM字节码甚至都不支持它。这意味着任何深度递归都是不可能的,你必须重构它以使用其他循环结构。
答案 3 :(得分:1)
如果您计算Collatz序列的大小,数字高达1,000,000 您应该重新考虑使用 整数 类型。我建议使用 BigInteger ,或者使用 long 。
这应该可以缓解遇到的问题,但是请注意,根据您的JVM,您可能仍然会耗尽堆空间。
答案 4 :(得分:1)
我认为你需要这两个提示:
哦,我忘记了什么。由于算术溢出,可能会发生堆栈溢出。由于您使用Integer,因此当算术溢出发生时,Java可能会将这些“飞行数字”“更改”为负数。并且如方法seqCount(int)中所示,您不检查不变量n&gt; 0
答案 5 :(得分:0)
您不仅可以通过递归解决此问题,还可以使用单个循环解决此问题。如果你写int,有溢出。因为它会产生很长时间的chaning并且递归永远不会结束因为永远不会等于1而你可能会得到 stackoverflow 错误
这是我的循环和递归解决方案:
public class Collatz {
public int getChainLength(long i) {
int count = 1;
while (i != 1) {
count++;
if (i % 2 == 0) {
i /= 2;
} else {
i = 3 * i + 1;
}
}
return count;
}
public static int getChainLength(long i, int count) {
if (i == 1) {
return count;
} else if (i % 2 == 0) {
return getChainLength(i / 2, count + 1);
} else {
return getChainLength(3 * i + 1, count + 1);
}
}
public int getLongestChain(int number) {
int longestChain[] = { 0, 0 };
for (int i = 1; i < number; i++) {
int chain = getChainLength(i);
if (longestChain[1] < chain) {
longestChain[0] = i;
longestChain[1] = chain;
}
}
return longestChain[0];
}
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(new Collatz().getLongestChain(1000000));
}
}
答案 6 :(得分:0)
在这里,您可以看看问题14的递归实现:
答案 7 :(得分:-1)
import java .util.*;
public class file
{
public static void main(String [] args)
{
long largest=0;
long number=0;
for( long i=106239;i<1000000;i=i+2)
{
long k=1;
long z=i;
while(z!=1)
{
if(z%2==0)
{
k++;
z=z/2;
} else{
k++;
z=3*z+1;
}
}
if(k>largest)
{
number=i;
largest=k;
System.out.println(number+" "+largest);
}
}//for loop
}//main
}