理解Kadane的二维数组算法

时间:2013-09-28 06:38:51

标签: java c++ kadanes-algorithm

我正在尝试编写一个解决maximum subarray problem的程序。我可以理解Kadane算法在1-D阵列上的直觉以及2-D阵列上的O(N ^ 4)实现。但是,我在理解二维阵列上的O(N ^ 3)实现时遇到了一些麻烦。

1)为什么我们将元素与同一列中前一行的元素相加?

for (int i = 1; i <= N; i++) {
  for (int j = 1; j <= M; j++) 
       array[i][j] += array[i-1][j];
}

2)我不了解算法的第二部分

试图在网上寻找解释,但无济于事。希望能在这里得到一些帮助!

提前致谢!

3 个答案:

答案 0 :(得分:6)

您知道如何使用Kadane算法计算一维阵列上的最大和子数组。现在我们想要为2D数组扩展这个算法。对于O(N ^ 3)算法,我们有直觉。如果我们以某种方式创建N ^ 2子问题,然后尝试运行我们的O(N)Kadane算法,我们就可以解决最大子数组问题。

因此,基本上我们如何创建N ^ 2子问题是通过迭代矩阵的所有顶行和底行。然后我们尝试通过应用kadane的1D算法找到子阵列之间存在的最佳列。因此,我们将这两行之间的数字相加,然后在这个新形成的1D数组上应用kadane的1D算法。

但我们这里有一个问题。计算顶行和底行的所有O(n ^ 2)范围的和本身将是O(n ^ 4)。可以通过修改我们的矩阵来克服这个瓶颈,方法是将每个元素替换为该元素列中位于其上方的所有数字的总和。因此,现在我们可以通过减去矩阵中的相应数组来找出O(n)时间内任意两行之间的数字之和。

java伪代码 -

    int kadane2D(int array[N+1][M+1]){

        // Modify the array's elements to now hold the sum  
        // of all the numbers that are above that element in its column 
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= M; j++){ 
                array[i][j] += array[i-1][j];
            }
        }


        int ans = 0;  // Holds the maximum sum matrix found till now

        for(int top=1; top<=N; top++){
            for(int bottom=top; bottom<=N; bottom++){
                // loop over all the N^2 sub problems
                int[] sums = new int[N+1];

                // store the sum of numbers between the two rows
                // in the sums array
                for(int i=0; i<=N; i++){
                    sums[i] = array[bottom][i] - array[top-1][i];
                }

                // O(n) time to run 1D kadane's on this sums array
                ans = Math.max(ans, kadane1d(sums));
            }
        }
        return ans;
    }

答案 1 :(得分:2)

我知道这是一个老问题。但谷歌没有正确的答案,或者他们过度工作。

不,这不是正确的方法。工作示例,关于O(N ^ 2):

  /**
  * Kadane 1d
  * @return max sum
  */
  public static int maxSum(int[] a) {
    int result = a[0]; //get first value for correct comparison
    int sum = a[0];
    for (int i = 1; i < a.length; i++) {
      sum = Math.max(sum + a[i], a[i]); //first step getting max sum, temporary value
      result = Math.max(result, sum);
    }
    return result;
  }

  /**
  * Kadane 2d
  * @param array
  * @return max sum
  */
  public static int maxSum2D(int array[][]){
    int result = Integer.MIN_VALUE; //result max sum
    for (int i = 0; i < array.length; i++) {
      int sum = maxSum(array[i]);
      result = Math.max(result, sum);
    }
    return result;
  }

完整的例子:

答案 2 :(得分:1)

对于了解 Kadane的一维算法的人,以下内容应该很容易理解。基本上,我们尝试通过对每行使用prefix sum将2D矩阵转换为1D。对于每个前缀和行,我们仅应用Kadane的1D算法。

只需发布有效的Python代码:

class Kadane2D:
    def maxSumRetangle(self, grid):
        def kadane1D(arr):
            curmax, maxsofar = 0, float('-inf')
            for a in arr:
                curmax = max(a, curmax + a)
                maxsofar = max(curmax, maxsofar)
            return maxsofar

        m, n, ans = len(grid), len(grid[0]), float('-inf')
        colCum = [[0] * n]
        for row in grid:
            colCum.append([pre + now for pre, now in zip(colCum[-1], row)])

        for top in range(1, m + 1):
            for bottom in range(top, m + 1):
                sums = [b - t for b, t in zip(colCum[bottom], colCum[top - 1])]
                ans = max(ans, kadane1D(sums))
        return ans


grid = [[1, 2, - 3], [3, 4, -6]]
assert Kadane2D().maxSumRetangle(grid) == 10
grid = [[1, 2, -1, -4, -20],
        [-8, -3, 4, 2, 1],
        [3, 8, 10, 1, 3],
        [-4, -1, 1, 7, -6]]
assert Kadane2D().maxSumRetangle(grid) == 29