最小步长到一
问题陈述:
对于正整数,可以执行以下 3 个步骤中的任何一个。
- 从中减去 1。( n = n - 1 )
- 如果可被 2 整除,则除以 2。( 如果 n % 2 == 0 ,则 n = n / 2 )
- 如果可被 3 整除,则除以 3。(如果 n % 3 == 0 ,则 n = n / 3 )。
现在的问题是,给定一个正整数n,找到需要n到1的最小步数
例如:
- 当 n = 1 时,输出:0
- 当 n = 4 时,输出: 2 ( 4 /2 = 2 /2 = 1 )
- 对于 n = 7,输出: 3 ( 7 -1 = 6 /3 = 2 /2 = 1 )
我知道使用动态编程和整数数组的解决方案。这是代码。
public int bottomup(int n) {
//here i am defining an integer array
//Exception is thrown here, if the n values is high.
public int[] bu = new int[n+1];
bu[0] = 0;
bu[1] = 0;
for(int i=2;i<=n;i++) {
int r = 1+bu[i-1];
if(i%2 == 0) r = Math.min(r,1+bu[i/2]);
if(i%3 == 0) r = Math.min(r,1+bu[i/3]);
bu[i] = r;
}
return bu[n];
}
但我想用更少的空间解决这个问题。如果 n=100000000,此解决方案会在 java 中抛出 OutofMemoryError。我不想增加堆空间。有没有人有使用更少空间的解决方案?
请注意,这个问题不能用贪婪的算法来解决。使用一个 while 循环并检查可整除的 3 和可被 2 整除是行不通的。您必须使用动态规划。请建议是否有任何解决方案使用更少的空间。
例如:
对于 n = 10 贪婪算法是 10 /2 = 5 -1 = 4 /2 = 2 /2 = 1,这需要 4 个步骤。其中解应该是 10-1 = 9 / 3 = 3 / 3 = 1,3 步。
我甚至尝试了自上而下的解决方案。
public int[] td = null;
public int topdown(int n) {
if(n <= 1) return 0;
int r = 1+topdown(n-1);
if(td[n] == 0) {
if(n%2 == 0) r = Math.min(r,1+topdown(n/2));
if(n%3 == 0) r = Math.min(r,1+topdown(n/3));
td[n] = r;
}
return td[n];
}
它在 n=10000 时失败。