Blog of CodeJELLOW’S ENGINEERING NOTES
← 返回文章

最大子矩阵

给定一个正整数和负整数组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。

本文目录 ⌄

    给定一个正整数和负整数组成的 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

    来源:力扣(LeetCode)

    题解

    最大子矩阵,可以先转化为求一行的最大字序列和,通过把这个问题升到二维解决。本题是一个DP问题。

    其实具体算法在算法书上已经有了,只不过书上的例题在均为负数时,最大值为0。而这道题如果均为负数,还要输出最大的负数,所以只要做一个小改动就好了,我写了一个算法,同时LeetCode上面还有一个更好的算法,在这里简单讲解一下。

    先看我写的(嘿嘿)

    TEXT
    #include <iostream>
    #include <vector>
    using namespace std;
    
    #define r 2
    #define l 2
    class Solution {
     public:
      int maxSubArray(vector<int>& nums, int& c1, int& c2) {
        int b = 0, sum = INT_MIN,c1_temp;
        for (int i = 0; i < nums.size(); i++) {
          if (b > 0) {
            b += nums[i];
          } else {
            b = nums[i];
            c1_temp = i;
          }
          if (b > sum ) {
            sum = b;
            c2 = i;
            c1=c1_temp;
          }
        }
        return sum;
      }
      vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
        int max, c1, c2, r1, r2, Max_final = INT_MIN, c1_final, c2_final;
        r1 = r2 = c1_final = c2_final =c1=c2= 0;
        vector<int> ans(4);
        for (int i = 0; i < matrix.size(); i++) {
          vector<int> li(matrix[0].size());  //默认值为0
          for (int j = i; j < matrix.size(); j++) {
            for (int k = 0; k < matrix[0].size(); k++) {
              li[k] += matrix[j][k];
            }
            max = maxSubArray(li, c1, c2);
            if (max > Max_final) {
              Max_final = max;
              r1 = i, r2 = j;
              c1_final = c1, c2_final = c2;
            }
          }
        }
        ans[0] = r1;
        ans[1] = c1_final;
        ans[2] = r2;
        ans[3] = c2_final;
        return ans;
      }
    };
    
    int main() {
      int array[r][l] = {-1, 0,0,-1};
      vector<vector<int>> matrix(r, vector<int>(l));
      for (int i = 0; i < r; i++) {
        for (int j = 0; j < l; j++) {
          matrix[i][j] = array[i][j];
        }
      }
      Solution s;
      s.getMaxMatrix(matrix);
    }

    因为自己测试了一下,实际上的算法只有class中的内容。

    maxSubArray用来计算一行的字序列最大值,输出列的范围

    getMaxMatrix通过调用maxSubArray,实现矩阵的计算。

    这个方法稍微有点麻烦在于,其实maxSubArray可以写进getMaxMatrix里,就有了下面这个程序,核心思想都是一样的。

    更新了算法的格式

    这样写比上面的更简洁

    TEXT
    
    /*
      1.动态规划,压缩成行矩阵
    */
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
      int m, n, MAX = 0, init_n, end_n;
      cin >> m >> n;
      vector<vector<int>> vec(m, vector<int>(n));
      vector<int> ans(4);
      for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
          cin >> vec[i][j];
        }
      }
      for (int i = 0; i < m; i++) {
        vector<int> dp(n);
        for (int j = i; j < m; j++) {
          int sum = 0, b = 0;
          for (int k = 0; k < n; k++) {
            dp[k] += vec[j][k];
            if (b > 0) {
              b += dp[k];
            } else {
              b = dp[k];
              init_n = k;
            }
            if (b > sum) {
              sum = b;
              end_n = k;
            }
          }
          if (sum > MAX) {
            MAX = sum;
            ans[0] = i;
            ans[1] = j;
            ans[2] = init_n;
            ans[3] = end_n;
          }
        }
      }
      cout << MAX<<endl;
      cout<<ans[0]+1;
      for(int i=1;i<4;i++){
        cout<<' '<<ans[i]+1;
      }
      system("pause");
    }

    每次移动k时计算当前列的最大序列,加完一行直接计算完成,减小了时间复杂度,也增加了程序的可读性。

    就到这里,有兴趣的可以再去实现一下。


    通过 RSS 订阅更新 →