Given a 2D array, find the maximum sum subarray in it. For example, in the following 2D array, the maximum sum subarray is highlighted with blue rectangle and sum of this subarray is 29.
This problem is mainly an extension of Largest Sum Contiguous Subarray for 1D array.
The naive solution for this problem is to check every possible rectangle in given 2D array. This solution requires 4 nested loops and time complexity of this solution would be O(n^4).
Kadane’s algorithm for 1D array can be used to reduce the time complexity to O(n^3). The idea is to fix the left and right columns one by one and find the maximum sum contiguous rows for every left and right column pair. We basically find top and bottom row numbers (which have maximum sum) for every fixed left and right column pair. To find the top and bottom row numbers, calculate sun of elements in every row from left to right and store these sums in an array say temp[]. So temp[i] indicates sum of elements from left to right in row i. If we apply Kadane’s 1D algorithm on temp[], and get the maximum sum subarray of temp, this maximum sum would be the maximum possible sum with left and right as boundary columns. To get the overall maximum sum, we compare this sum with the maximum sum so far.
用Kadane算法把原来O(n4)复杂度降低到O(n3)
package DP; import java.util.Arrays; public class MaxSumRectangleIn2DMatrix { public static void main(String[] args) { int[][] M = { {1, 2, -1, -4, -20}, {-8, -3, 4, 2, 1}, {3, 8, 10, 1, 3}, {-4, -1, 1, 7, -6} }; findMaxSum(M); } // Time Complexity: O(n^3) public static void findMaxSum(int[][] M){ int maxSum = Integer.MIN_VALUE; int finalLeft = 0, finalRight = 0, finalTop = 0, finalBottom = 0; int ROW = M.length, COL = M[0].length; int[] temp = new int[ROW]; int[] startFinnish = {0, 0}; // [0]:start值,[1]:finnish值 // Set the left column for(int left=0; left<COL; left++){ // 从左边开始的列号 Arrays.fill(temp, 0); // 每次重新开始计算时必须清空temp // Set the right column for the left column set by outer loop for(int right=left; right<COL; right++){ // 到右边结束的列号 // Calculate sum between current left and right for every row 'i' for(int i=0; i<ROW; i++){ // 把当前检测的那“一列”放在temp数组中(temp[i] = M[i][right];) temp[i] += M[i][right]; // 那“一列”随着右边结束行号的扩大而不断横向累加(temp[i] += M[i][right];) } // Find the maximum sum subarray in temp[]. The kadane() function // also sets values of start and finish. So 'sum' is sum of // rectangle between (start, left) and (finish, right) which is the // maximum sum with boundary columns strictly as left and right. int sum = kadane(temp, startFinnish, ROW); // 计算temp中的最大连续数组 // Compare sum with maximum sum so far. If sum is more, then update // maxSum and other output values if(sum > maxSum){ // 保存全局最优值 maxSum = sum; finalLeft = left; finalRight = right; finalTop = startFinnish[0]; finalBottom = startFinnish[1]; } } } System.out.format("(Top, Left) (%d, %d)\n", finalTop, finalLeft); System.out.format("(Bottom, Right) (%d, %d)\n", finalBottom, finalRight); System.out.format("Max sum is: %d\n", maxSum); } // Implementation of Kadane's algorithm for 1D array. The function returns the // maximum sum and stores starting and ending indexes of the maximum sum subarray // at addresses pointed by start and finish pointers respectively. private static int kadane(int[] A, int[] startFinnish, int n) { int sum = 0, maxSum = Integer.MIN_VALUE; startFinnish[1] = -1; // Just some initial value to check for all negative values case int localStart = 0; for(int i=0; i<n; i++){ sum += A[i]; if(sum < 0){ sum =0; localStart = i+1; }else if(sum > maxSum){ maxSum = sum; startFinnish[0] = localStart; startFinnish[1] = i; } } if(startFinnish[1] != -1){ // There is at-least one non-negative number return maxSum; } maxSum = A[0]; // Special Case: When all numbers in arr[] are negative startFinnish[0] = startFinnish[1] = 0; for(int i=1; i<n; i++){ // Find the maximum element in array if(A[i] > maxSum){ maxSum = A[i]; startFinnish[0] = startFinnish[1] = i; } } return maxSum; } }