最大子矩阵
难度:
标签:
题目描述
Given an NxM matrix of positive and negative integers, write code to find the submatrix with the largest possible sum.
Return an array [r1, c1, r2, c2]
, where r1
, c1
are the row number and the column number of the submatrix's upper left corner respectively, and r2
, c2
are the row number of and the column number of lower right corner. If there are more than one answers, return any one of them.
Note: This problem is slightly different from the original one in the book.
Example:
Input:
[
[-1,0],
[0,-1]
]
Output: [0,1,0,1]
Note:
1 <= matrix.length, matrix[0].length <= 200
代码结果
运行时间: 936 ms, 内存: 18.8 MB
/*
* 思路:
* 使用动态规划和Kadane算法来解决这个问题。
* 这里使用Java Stream API实现。
* 首先,将每一列的元素累加起来,然后使用Kadane算法在累加数组上找出最大子数组和。
* 在找出最大子数组和的同时,记录对应的行索引。
* 最后,通过累加的列索引和Kadane算法得到的行索引确定最大子矩阵的左上角和右下角。
*/
import java.util.stream.IntStream;
public class Solution {
public int[] getMaxMatrix(int[][] matrix) {
int row = matrix.length;
int col = matrix[0].length;
int[] result = new int[4];
int maxSum = Integer.MIN_VALUE;
for (int left = 0; left < col; left++) {
int[] rowSum = new int[row];
for (int right = left; right < col; right++) {
IntStream.range(0, row).forEach(i -> rowSum[i] += matrix[i][right]);
int[] tempResult = kadane(rowSum);
if (tempResult[2] > maxSum) {
maxSum = tempResult[2];
result[0] = tempResult[0];
result[1] = left;
result[2] = tempResult[1];
result[3] = right;
}
}
}
return result;
}
private int[] kadane(int[] array) {
int start = 0, end = 0, tempStart = 0, maxSum = array[0], sum = array[0];
for (int i = 1; i < array.length; i++) {
if (sum < 0) {
sum = array[i];
tempStart = i;
} else {
sum += array[i];
}
if (sum > maxSum) {
maxSum = sum;
start = tempStart;
end = i;
}
}
return new int[] {start, end, maxSum};
}
}
解释
方法:
这个问题可以通过将二维问题转化为一维问题来解决。首先,我们通过计算矩阵的纵向前缀和来简化区间求和的操作。然后,通过固定子矩阵的上下界(top 和 bottom),将问题转换为求解固定行区间内部的最大子数组和,这一步使用类似Kadane算法的动态规划方法。对于每一对上下界,我们遍历所有可能的左右边界,计算这个矩形区间的和,并更新最大值。如果当前的累积和为负数,则重新开始计算新的子数组,否则继续累加。
时间复杂度:
O(H^2 * W)
空间复杂度:
O(H * W)
代码细节讲解
🦆
在转换二维问题为一维问题的过程中,你是如何选择纵向前缀和而不是横向前缀和?
▷🦆
纵向前缀和的计算为何从索引1开始而不是0?这样做有什么特殊的考虑吗?
▷🦆
在使用类似Kadane算法求解最大子数组和时,如果当前累积和为负数直接重置,这种情况下是否有可能错过最优解?
▷