【发布时间】:2013-12-31 02:11:53
【问题描述】:
问题陈述:
对于一个正整数,您可以执行以下 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 时失败。
【问题讨论】:
-
这样做的一种方法,因为步数是 O(log(n)),你可以使用 short 而不是 int 作为 int 输入。
-
和@elyashiv 一样,byte 也够用了。
-
您希望能够处理多高的
n?空间方面的考虑可能为什么像SPOJ 这样的练习将其限制为(0 < n ≤ 2*10^7 )。 -
char优于short,因为答案永远不会是否定的。chars 未签名,shorts 已签名。 -
我认为short可以签名。
标签: java algorithm math dynamic-programming