题目描述
给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。
返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
注意:本题相对书上原题稍作改动
示例:
输入:
[
[-1,0],
[0,-1]
]
输出:[0,1,0,1]
解释:输入中标粗的元素即为输出所表示的矩阵说明:
1 <= matrix.length, matrix[0].length <= 200
算法分析
问题从一维变成了二维,但实质是一样的,同样是再求最大子序和,我们需要将二维转化为一维,对于矩阵的每一列,我们将其加在一起,成为了一维上的一个数,二维矩阵的和转化为了一维数组的和
这样我们就将二维问题转化为了一维问题,现在另一个问题就是怎么把所有情况都遍历到呢?
我们以第i行为第一行,向下延申,设最后一行为第j行,我们就i在这么一个范围内,将二维问题转化为一维问题,再求解最大子序列和
我们将当前i~j行组成的矩阵的每一列的和存放在数组b中,其余的工作就是在求最大子序列和,并且保存其左上角和右下角
代码
class Solution {
public:
vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
int rows=matrix.size(), cols=matrix[0].size();
int maxMat=INT32_MIN;
vector<int> ans(4, -1);
for(int r1=0;r1<rows;++r1){//遍历起始行
vector<int> nums(cols);//矩阵某两行间元素按列求和
for(int r2=r1;r2<rows;++r2){//遍历结束行
//最大字段和问题
int dp=0, c1=-1;
for(int c2=0;c2<cols;++c2){//遍历和数组,实际上是边遍历边完成求和
nums[c2]+=matrix[r2][c2];//将新的一行中第i个元素加到前面若干行在位置i的和
if(dp>0){//前面的字段有和为正,可以把前面一部分也带上
dp+=nums[c2];
}
else{//前面一段为负,拖后腿直接抛弃
dp=nums[c2];
c1=c2;
}
if(dp>maxMat){//不断记录较好的结果
maxMat=dp;
ans[0]=r1;
ans[1]=c1;
ans[2]=r2;
ans[3]=c2;
}
}
}
}
return ans;
}
};
算法复杂度分析
时间复杂度:o(n^2*m)
空间复杂度:o(m)
m = rows, n = cols