【问题标题】:Why is the maximum sum subarray brute force O(n^2)?为什么最大和子数组蛮力O(n ^ 2)?
【发布时间】:2017-06-13 18:30:12
【问题描述】:

maximum subarray sum 是计算机科学中的著名问题。

至少有两种解决方案:

  1. 蛮力,找到所有可能的子数组,找到最大值。
  2. 使用Karanes Algorithm 的变体来计算全局最大值,同时通过数组的第一遍。

在视频tutorial中,作者提到蛮力方法是O(n^2),阅读another answer一个人认为是O(n^2),另一个认为是O(n^3)

蛮力是O(n^2)还是O(n^3)?更重要的是,您能否说明您对蛮力方法进行了哪些分析才能知道它是O(?)

【问题讨论】:

    标签: arrays algorithm computer-science


    【解决方案1】:

    这可以用 O(N) 来完成,如下所示!!! 我错过了什么吗?

        int[] arr = {}; //elements;
        int max = 0, temp = 0;
        for (int i = 0; i < arr.length; i++) {
            temp = Math.max(arr[i], arr[i] + temp);
            max = Math.max(temp, max);
        }
        System.out.println(max); //result
    

    【讨论】:

    • 那是Kadane的算法,问题中提到了。
    【解决方案2】:

    嗯,这取决于武力有多强。

    如果我们生成所有(i, j): i &lt;= j对并计算它们之间的和,则为O(n^3)

    ....
    for (int i = 0; i < n; i++)
        for (int j = i; j < n; j++) {
            int sum = 0;
            for (int k = i; k <= j; k++)
                sum += a[k];
            if (sum > max)
                max = sum;
        }
    

    如果我们从所有位置开始计算运行总和,则为O(n^2)

    ....
    for(int i = 0; i < n; i++) {
        int sum = 0;
        for (int j = i; j < n; j++) {
            sum += a[j];
            if (sum > max)
                max = sum;
        }
    }
    

    【讨论】:

    • 非常感谢您描述这两种蛮力解决方案!你介意解释一下你是如何知道哪个是 O(n^2) 哪个是 O(n^3)
    • @mbigras 注意嵌套循环的数量作为一阶近似值。
    • 啊,我明白了,嵌套循环大致决定了复杂性。当他声称他的蛮力方法是O(n^2)here时,教程的作者是不是弄错了?
    • 它可以是任意的,因为它没有解释如何计算数组总和。算完的话就是n^3,如果用之前的sum就是n^2
    【解决方案3】:

    这里是最大子数组和问题的三个解决方案。 solve1() 运行时间为 O(N),solve2() 运行时间为 O(N^2),solve3() 运行时间为 O(N^3)。请注意,solve1() 被称为 Kadane 算法。

    O(N^2) 和 O(N^3) 函数之间的区别在于,在 O(N^2) 函数中,每次增加 end 索引时都会隐式计算总和,而在O(N^3) 函数,通过startend 之间的第三个显式循环计算总和。

    我还为所有三种方法添加了代码,以处理所有输入值为负数的情况。

    public class MaximumSubarraySum {
    
        /**
         * Solves the maximum subarray sum in O(N) time.
         */
        public static int solve1(int[] input) {
    
            int sum = input[0];
            int bestSum = sum;
    
            for (int i = 1; i < input.length; i++) {
                sum = Math.max(input[i], input[i] + sum);
                bestSum = Math.max(sum, bestSum);
            }
    
            return bestSum;
        }
    
        /**
         * Solves the maximum subarray sum in O(N^2) time. The two indices
         * 'start' and 'end' iterate over all possible N^2 index pairs, with 
         * the sum of input[start, end] always computed for every 'end' value. 
         */
        public static int solve2(int[] input) {
    
            int bestSum = -Integer.MAX_VALUE;
    
            for (int start = 0; start < input.length; start++) {
    
                // Compute the sum of input[start, end] and update
                // 'bestSum' if we found a new max subarray sum.
    
                // Set the sum to initial input value to handle edge case
                // of all the values being negative.
                int sum = input[start];
                bestSum = Math.max(sum, bestSum);
    
                for (int end = start+1; end < input.length; end++) {
                    sum += input[end];
                    bestSum = Math.max(sum, bestSum);
                }
            }
    
            return bestSum;
        }
    
        /**
         * Solves the maximum subarray sum in O(N^3) time. The two indices
         * 'start' and 'end' iterate over all possible N^2 index pairs, and
         * a third loop with index 'mid' iterates between them to compute 
         * the sum of input[start, end].
         */
        public static int solve3(int[] input) {
    
            int bestSum = -Integer.MAX_VALUE;
    
            for (int start = 0; start < input.length; start++) {
    
                for (int end = start; end < input.length; end++) {
    
                    // Compute the sum of input[start, end] using a third loop
                    // with index 'mid'. Update 'bestSum' if we found a new 
                    // max subarray sum.
    
                    // Set the sum to initial input value to handle edge case
                    // of all the values being negative.
                    int sum = input[start];
                    bestSum = Math.max(sum, bestSum);
    
                    for (int mid = start+1; mid < end; mid++) {
                        sum = Math.max(input[mid], input[mid] + sum);
                        bestSum = Math.max(sum, bestSum);
                    }
                }
            }
    
            return bestSum;
        }
    
    
        public static void runTest(int[] input) {
    
            System.out.printf("\n");
            System.out.printf("Input: ");
            for (int i = 0; i < input.length; i++) {
                System.out.printf("%2d", input[i]);
                if (i < input.length-1) {
                    System.out.printf(", ");
                }
            }
            System.out.printf("\n");
    
            int result = 0;
    
            result = MaximumSubarraySum.solve1(input);
            System.out.printf("solve1 result = %d\n", result);
    
            result = MaximumSubarraySum.solve2(input);
            System.out.printf("solve2 result = %d\n", result);
    
            result = MaximumSubarraySum.solve3(input);
            System.out.printf("solve3 result = %d\n", result);
    
        }
    
    
        public static void main(String argv[]) {
    
            int[] test1 = { -2, -3,  4, -1, -2, -1, -5, -3 };
            runTest(test1);
    
            int[] test2 = { -2, -3, -4, -1, -2, -1, -5,  3 };
            runTest(test2);
    
            int[] test3 = { -2, -3, -4, -1, -2, -1, -5, -3 };
            runTest(test3);
    
            int[] test4 = { -2, -3,  4, -1, -2,  1,  5, -3 };
            runTest(test4);  
        }
    }
    

    输出是:

    Input: -2, -3,  4, -1, -2, -1, -5, -3
    solve1 result = 4
    solve2 result = 4
    solve3 result = 4
    
    Input: -2, -3, -4, -1, -2, -1, -5,  3
    solve1 result = 3
    solve2 result = 3
    solve3 result = 3
    
    Input: -2, -3, -4, -1, -2, -1, -5, -3
    solve1 result = -1
    solve2 result = -1
    solve3 result = -1
    
    Input: -2, -3,  4, -1, -2,  1,  5, -3
    solve1 result = 7
    solve2 result = 7
    solve3 result = 7
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      • 2020-05-30
      • 2015-05-25
      • 1970-01-01
      • 2020-12-16
      • 1970-01-01
      相关资源
      最近更新 更多