Algorithmic complexity of naive code for processing all consecutive subsequences of a list: n^2 or n^3?

前端 未结 9 1024
傲寒
傲寒 2020-12-25 11:41

I\'m studying for a test and found this question:

I can\'t really determine the complexity, I figured it\'s either O(n2) or O(n3) and I\'m lea

相关标签:
9条回答
  • 2020-12-25 12:04

    The complete reasoning is as follows:

    Let n be the length of the array.

    1) There are three nested loops.

    2) The innermost loop performs exactly j-i iterations (k running from i+1 to j inclusive). There is no premature exit from this loop.

    3) The middle loop performs exactly n-j iterations (j running from i to n-1 inclusive), each involving j-i innermost iterations, in total (i-i)+(i+1-i)+(i+2-i)+... (n-1-i) = 0+1+2... + (n-1-i). There is no premature exit from this loop.

    4) The outermost loop performs exactly n iterations (i running from 0 to n-1 inclusive), each involving 0+1+2+ ... (n-1-i) innermost iterations. In total, (0+1+2... n-1) + (0+1+2+... n-2) + (0+1+2+... n-3) + ... (0). There is no premature exit from this loop.

    Now how do handle handle this mess ? You need to know a little about the Faulhaber's formula (http://en.wikipedia.org/wiki/Faulhaber%27s_formula). In a nutshell, it says that the sum of integers up to n is O(n^2); and the sum of the sum of integers up to n is O(n^3), and so on.

    If you recall from calculus, the primitive of X is X^2/2; and the primitive of X^2 is X^3/3. Every time the degree increases. This is not by coincidence.

    Your code runs in O(n^3).

    0 讨论(0)
  • 2020-12-25 12:10

    If you do not feel well-versed enough in the underlying theory to directly apply @MohamedEnnahdiElIdri's analysis, why not simply start by testing the code?

    Note first that the loop boundaries only depend on the array's length, not its content, so regarding the time complexity, it does not matter what the algorithm does. You might as well analyse the time complexity of

    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;
    }
    

    Looking at this, is it easier to derive a hypothesis? If not, simply test whether the return value is proportional to length squared or length cubed...

    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);
      }
    }
    

    ... and notice how one value does not approach anyconstant with rising l and the other one does (not incidentally the very same constant associated with the highest power of $n$ in the methodological analysis).

    0 讨论(0)
  • 2020-12-25 12:11

    No matter triangle shape or not, it always a complexity O(N^3), but of course with lower constant then a full triple nested cycles.

    0 讨论(0)
  • 2020-12-25 12:16

    You can proceed methodically, using Sigma Notation, to obtain the order of growth complexity:

    enter image description here

    0 讨论(0)
  • 2020-12-25 12:17

    You can model the running time of the function as

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

    As

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

    the running time is Theta(n^3).

    0 讨论(0)
  • 2020-12-25 12:21

    This requires O(n^3) time due to the fact that in the three loops, three distinct variables are incremented. That is, when one inside loop is over, it does not affect the outer loop. The outer loop runs as many times it was to run before the inner loop was entered.

    And this is the maximum contiguous subarray sum problem. Self-explanatory when you see the example:

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

    There is an excellent algorithm known as Kadane's algorithm (do google for it) which solves this in O(n) time.

    Here it goes:

    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
    

    References: 1, 2, 3.

    0 讨论(0)
提交回复
热议问题