产生数字等于一组数字的最坏情况复杂性

时间:2014-05-11 18:44:58

标签: java algorithm

以下是我的代码;我很擅长分析递归函数;我认为这是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";
      }
  }

3 个答案:

答案 0 :(得分:1)

首先,请注意变量n在此问题的上下文中没有定义的含义,因此将算法的运行时表示为n的函数是没有意义的。

其次,请注意,如果

,您的算法只有合理的终止行为
  • a和b为正OR
  • 即使是初始a,b我们也有+ b> min {c,d}

后一种情况并不是特别有趣,所以让我们专注于前一种情况。特别地,在这种情况下,我们有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的函数

enter image description here

此时我不确定如何精确地建立此函数的渐近线。去除共同性质约束和地板后得到的快速上限是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)。