用于处理列表的所有连续子序列的朴素代码的算法复杂度:n ^ 2或n ^ 3?

时间:2014-04-02 07:19:31

标签: java algorithm time-complexity big-o

我正在学习考试并找到了这个问题:

我无法确定复杂性,我认为它是O(n 2 )或O(n 3 )和我&# 39; m倾向于O(n 3 ) 有人可以告诉我它是什么以及为什么?

我认为它的O(n 2 )是因为在j循环中,j = i给出了三角形,然后是{{ 1}}循环从k转到i + 1,我认为这是三角形的另一半。

j

另外,如果你能告诉我它的作用?

我认为它返回正整数的加法或数组中的最大整数 但对于像public static int what(int[] arr) { int m = arr[0]; for (int i=0; i<arr.length; i++) { for (int j=i; j<arr.length;j++) { int s = arr[i]; for (int k=i+1; k<=j; k++) s += arr[k]; if (s > m) m = s; } } return m; } 这样的数组,它会返回{99, -3, 0, 1},我认为这是因为它有问题。如果不是我不知道它做了什么:

99

9 个答案:

答案 0 :(得分:49)

您可以使用Sigma Notation有条不紊地处理增长复杂性的顺序:

enter image description here

答案 1 :(得分:15)

你有3个陈述。对于较大的n,很明显是O(n^3)ij各有O(n)k稍短,但仍为O(n).

算法返回连续项的最大总和。这就是为什么最后一个它返回99,即使你有0和1,你也有-3将你的总和降到最多97.

PS:三角形意味着1 + 2 + ... + n = n(n+1) / 2 = O(n^2)

答案 2 :(得分:9)

<强>代码:

for (int i=0; i<arr.length; i++) // Loop A
{
    for (int j=i; j<arr.length;j++) // Loop B
    {
        for (int k=i+1; k<=j; k++) // Loop C
        {
            // ..
        }
    }
}

Big-O的渐近分析:

Loop A: Time = 1 + 1 + 1 + .. 1 (n times) = n

Loop B+C: Time = 1 + 2 + 3 + .. + m = m(m+1)/2

Time = SUM { m(m+1)/2 | m in (n,0] }

Time < n * (n(n+1)/2) = 1/2 n^2 * (n+1) = 1/2 n^3 + 1/2 n^2

Time ~ O(n^3)

答案 3 :(得分:3)

无论是否为三角形,它总是复杂度为O(N ^ 3),但当然具有较低的常数,然后是完整的三重嵌套循环。

答案 4 :(得分:3)

您可以将函数的运行时间建模为

sum(sum(sum(Theta(1), k=i+1..j),j=i..n),i=1..n)

作为

sum(sum(sum(1, k=i+1..j),j=i..n),i=1..n) = 1/6 n^3  - 1/6 n,

运行时间是Theta(n ^ 3)。

答案 5 :(得分:3)

为O(n ^ 3)。

你计算了 arr [0]和arr [arr.length - 1] 之间的任意两项,由“i”和“j”运行,这意味着C(n,2),这是n *(n + 1)/ 2次计算。

以“k”运行的每个计算之间的平均步长是(0 + arr.length)/ 2,因此总计算时间为C(n,2)* arr.length / 2 = n * n *(n + 1)/ 4,即O(n ^ 3)。

答案 6 :(得分:3)

如果你不熟悉基础理论直接应用@ MohamedEnnahdiElIdri的分析,为什么不简单地从测试代码开始呢?

首先请注意,循环边界仅取决于数组的长度,而不取决于其内容,因此关于时间复杂度,算法的作用并不重要。您也可以分析

的时间复杂度
public static long countwhat(int length) {
  long count = 0;
  for (int i = 0; i < length; i++) {
    for (int j = i; j < length; j++) {
      for (int k = i + 1; k <= j; k++) {
        count++;
      }
    }
  }
  return count;
}

考虑到这一点,推导假设是否更容易?如果没有,只需测试返回值是否与length平方或length立方体成正比...

public static void main(String[] args) {
  for (int l = 1; l <= 10000; l *= 2) {
    long count = countwhat(l);
    System.out.println("i=" + l + ", #iterations:" + count + 
      ", #it/n²:" + (double) count / l / l +
      ", #it/n³:" + (double) count /  l / l / l);
  }
}

...并注意一个值如何不接近任何常数上升l而另一个值接近(不是偶然地与方法分析中与$ n $的最高幂相关联的常数)。< / p>

答案 7 :(得分:3)

这需要O(n^3)时间,因为在三个循环中,三个不同的变量递增。也就是说,当一个内部循环结束时,它不会影响外部循环。外循环运行的次数是在输入内循环之前运行的次数。

这是最大的连续子阵列和问题。当你看到这个例子时,不言自明:

{99, 1} => returns 100
{-1, -2, -3} => return -1
{-1, 5, -2} => returns 5
{99, -3, 0, 1} => returns 99

有一种很好的算法,称为Kadane的算法(谷歌为它),它在O(n)时间内解决了这个问题。

这就是:

Initialize:
    max_so_far = 0
    max_ending_here = 0

Loop for each element of the array
  (a) max_ending_here = max_ending_here + a[i]
  (b) if(max_ending_here < 0)
            max_ending_here = 0
  (c) if(max_so_far < max_ending_here)
            max_so_far = max_ending_here
return max_so_far

参考文献:123

答案 8 :(得分:2)

完整的推理如下:

n为数组的长度。

1)有三个嵌套循环。

2)最里面的循环执行完全j-i次迭代(ki+1j,包括在内。这个循环没有过早退出。

3)中间循环执行完全n-j次迭代(jin-1包含),每次迭代都涉及j-i最里面的迭代(i-i)+(i+1-i)+(i+2-i)+... (n-1-i) = 0+1+2... + (n-1-i)。这个循环没有过早退出。

4)最外层循环执行完全n次迭代(从i0包括n-1),每次迭代都涉及0+1+2+ ... (n-1-i)最里面的迭代。总共(0+1+2... n-1) + (0+1+2+... n-2) + (0+1+2+... n-3) + ... (0)。这个循环没有过早退出。

现在怎么处理这个烂摊子?你需要了解一下Faulhaber的公式(http://en.wikipedia.org/wiki/Faulhaber%27s_formula)。简而言之,它表示最多n的整数之和为O(n^2);并且n之前的整数之和为O(n^3),依此类推。

如果你从微积分中回忆起来,X的原语是X^2/2; X^2的原语是X^3/3。每次学位增加。这不是巧合。

您的代码在O(n^3)中运行。