难度困难171收藏分享切换为英文接收动态反馈
给定一个正整数、负整数和 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行的子矩阵,将此范围内的每一列的元素和看作是最大子段和问题中数组的一个元素,应用最大子段和问题的dp算法。
AC代码:
class Solution {
static const int MAX_SIZE=1e3+1;
int Mat[MAX_SIZE][MAX_SIZE];
int tmp[MAX_SIZE][MAX_SIZE]; //辅助矩阵,tmp[i][j]存储的是前i行的第j列的累加之和
int b[MAX_SIZE]; //b[k] 存放的是当前第i行到第j行的范围内第k列的元素和
int m,n;
public:
vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
m=matrix.size();
n=matrix[0].size();
//初始化tmp
for(int i=0;i<n;i++)
tmp[0][i]=matrix[0][i];
for(int i=1;i<m;i++){
for(int k=0;k<n;k++){ //计算每一列的前i行的元素之和
tmp[i][k]=tmp[i-1][k]+matrix[i][k];
}
}
int row0,row1;
int line0,line1;
int maxsum=INT_MIN;
for(int i=0;i<m;i++){
for(int j=i;j<m;j++){
// cursum存放当前第i行到第j行的范围内 前k列的最大元素和
int cursum=0;
int curR0=0,curR1=0;
for(int k=0;k<n;k++){
if(i==0)
b[k]=tmp[j][k];
else
b[k]=tmp[j][k]-tmp[i-1][k];
//计算第i行到第j行的累加之和
if(b[k]+cursum>b[k]){//更新列的边界
cursum=b[k]+cursum;
curR1=k;
}else{
cursum=b[k]; //在第k列从头开始
curR0=curR1=k;
}
if(cursum>maxsum){
maxsum=cursum;
//更新子矩阵行列的边界
row0=curR0;
row1=curR1;
line0=i;
line1=j;
}
}
}
}
vector<int> res;
res.push_back(line0);
res.push_back(row0);
res.push_back(line1);
res.push_back(row1);
return res;
}
};
参考文献: