以下是我的代码;我很擅长分析递归函数;我认为这是O(2 ^ n);你们有什么感想? (我知道你可以写得更好,我的问题是关于下面代码的运行时间)。
static int ans = 0;
public static void ablehelper(int a, int b, int c, int d){
if(a != c && (b + a) > c){
return;
}
if(b != d && (b + a) > d){
return;
}
if(a == c && b == d){
ans = 1;
return;
}
ablehelper(a + b, b, c, d);
ablehelper(a, b + a, c, d);
}
public static String able(int a, int b, int c, int d){
ablehelper(a, b, c, d);
if(ans == 1){
return "Able to generate";
}else{
return "Not table to generate";
}
}
答案 0 :(得分:1)
首先,请注意变量n在此问题的上下文中没有定义的含义,因此将算法的运行时表示为n的函数是没有意义的。
其次,请注意,如果
,您的算法只有合理的终止行为后一种情况并不是特别有趣,所以让我们专注于前一种情况。特别地,在这种情况下,我们有a,b> = 1。
对(c,d)在每次递归期间保持固定,所以让我们看看你的算法枚举的对(a,b)的性质是什么。设A和B为a和b的初始值。我们在每个函数调用中都有,(a,b)=(x1 * A + y1 * B,x2 * A + y2 * B)。过渡是
((x1 + x2) * A + (y1 + y2) * B, x2 * A + y2 * B)
(x1 * A + y1 * B, (x1 + x2) * A + (y1 + y2) * B)
我们可以证明函数f(x1,y1,x2,y2)=(x1 + x2,y1 + y2)在被限制为执行期间出现的值(x1,y1,x2,y2)时是单射的算法。
如果我们查看完整的递归树,没有修剪,f采用以下值:
(1,1)
(1,2)
(1,3)
...
(2,1)
(2,3)
(2,5)
(2,7)
...
(3,1)
(3,2)
(3,4)
(3,5)
(3,7)
...
注意模式?我们可以证明f恰好采用值对(x,y)和gcd(x,y)= 1(互质对)。此外,由于修剪,我们只用Ax + By< = min {c,d}枚举那些对(x,y)。因此,算法的运行时间T表示为A,B,c和d的函数
此时我不确定如何精确地建立此函数的渐近线。去除共同性质约束和地板后得到的快速上限是T(A,B,c,d)= O(min {c,d} ^ 2 /(A * B) )= O(min {c,d} ^ 2)。不确定这个界限有多紧。
更新:在您的CR帖子中,您提出了一个更好的算法来解决问题。它仍然包含一个错误,但它是一个好的开始:
public static String betterSolution(int a, int b, int c, int d){
while( c > a || d > b){
if(c > d){
if (d == 0) break; // otherwise, it does not terminate!
c = c-d;
}else{
if (c == 0) break; // otherwise, it does not terminate!
d = d-c;
}
}
if( c == a && d == b){
return "Able to generate";
}else{
return "Not able to generate";
}
}
该算法在变量中仍然只是多项式,O(max {c,d})是精确的。您可以通过“跳过”步骤将其提高到对数时间:
public static String evenBetterSolution(int a, int b, int c, int d){
while( c > a || d > b){
if(c > d){
if (d == 0) break;
c = c - Math.max(1, (c - a) / d) * d;
}else{
if (c == 0) break;
d = d - Math.max(1, (d - b) / c) * c;
}
}
if( c == a && d == b){
return "Able to generate";
}else{
return "Not able to generate";
}
}
算法基于Euclidean GCD algorithm,运行时以O(log(min {c,d})为界)。很好。
答案 1 :(得分:0)
让我们说:
a = -1 b = 0 c = 0 d = 0
这些值将跳过第一个if,第二个if和第三个if和将直接转到
能够帮助(a + b,b,c,d);
事实证明-1 + 0是-1,因此,我们从头开始,这没有结束(但是堆栈溢出异常)。
关于复杂性,它没有像Marco Acierno指出的那样有道理。
答案 2 :(得分:0)
这让我想起了最近的TopCoder problem,所以我会假设声明的缺失部分来自那里。所以,我会回答以下问题:
让 a , b , c 和 d 是来自 1 的整数到 n ,包括在内。什么 是编码算法相对于 n 的时间复杂度?
我说这是O(n ^ 2)。了解 c 和 d 如何保持不变,但 a 和 b 增长。如果(最坏情况) a = b = 1 且 c = d = n ,我们将访问每对(a,b)其中 a + b <= n 不超过一次。要了解原因,请考虑一对(a,b)并回顾它是如何生成的。事实证明,一对(a,b)其中 a&gt; b 只能由(a - b,b)生成,如果 a&lt; b 它只能由(a,b - a)生成。否则,其中一个值将为负数,因为我们从正 a 和 b 开始,所以它们在整个过程中保持为正。
更确切地说,当我们从 a = b = 1 开始时,我们访问每对(a,b),其中 a <的最大公约数/ em>和 b 只有 1 一次,并且不会访问任何其他对。 The number这样的对是〜6n ^ 2 / PI ^ 2,即Θ(n ^ 2)。