最大子矩阵

239 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

最大子矩阵(单串动态规划)

题目描述

给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。

示例

//输入
[ [-1,0],
  [0,-1]
         ]
//输出
[0,1,0,1]

思路分析

  1. i 记录开始行,从0开始~最后一行
  2. j 记录结束行,从i开始~最后一行
  3. 计算 i 行~ j 行中各列元素的和存储到以数组中
  4. 此时二维问题化成一维问题,即求矩阵的最大<==>求列和数组的最大子序列

图解

3db064ede3bc148f63d04c48fc8f852bf0e5a3e9d7ddbf58c8d526f201f08075-捕获.jpg

代码实现

   //记录坐标,所以不能直接使用max函数
   class Solution {
public:
    vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
        //获取n行m列
        int n=matrix.size(),m=matrix[0].size();
        //sum记录i行~j行的列和数组中各子段的和
        int sum=0;
        //分别记录开始列坐标、开始行坐标和最大值(注:最大值不能设0,要设足够小,因为矩阵中会有负数)
        int be_col=0,be_row=0,maxnum=INT_MIN;
        //列和数组和记录坐标数组
        vector<int> col_sum(m),local(4);
        //i控制开始行
        for(int i=0;i<n;i++){
            //每次开始行变动,列和数组就更新为0
            for(int t=0;t<m;t++ ) col_sum[t]=0; 
            //j控制结束行
            for(int j=i;j<n;j++){
                //每次结束行向下移动一层,记录列和数组的sum就更新为0
                sum=0;
                //j向下移动一层之后,各列和只需在原来的基础上加上最下面一行的各列元素
                for(int c=0;c<m;c++)
                    //计算出i行~j行的列和数组
                    col_sum[c]+=matrix[j][c];
               //求最大矩阵等价于求列和数组的最大子段和,并记录位置
                for(int k=0;k<m;k++){
                    //k值记录列元素
                    if(sum>0)
                        sum+=col_sum[k];
                    else{
                        sum=col_sum[k];
                        be_col=k;
                        be_row=i;}
                    if(sum>maxnum){
                        maxnum=sum;
                        local[0]=be_row;
                        local[1]=be_col;
                        local[2]=j;
                        //结束列即当前列
                        local[3]=k;}
                    }     
            }
}
       return local;
}
};