二维最大子矩阵和核心解法:枚举所有上下边界组合,每一组组合对应压缩一维数组,再跑一次Kadane算法,本质是降维思想,时间复杂度O(n³),通用且易懂。
一、核心逻辑(必记)
子矩阵由上下左右四边界确定,直接枚举四边界复杂度O(n⁴),优化思路:
-
枚举所有上下边界[i,j](O(n²)),固定行区间;
-
将[i,j]行的每一列求和,压缩为一维数组arr;
-
对arr跑Kadane算法(O(n)),得到当前[i,j]下的最优左右边界;
-
所有组合的Kadane结果取最大值,即为全局最大子矩阵和。
二、核心步骤(极简版)
Step 1:预处理列前缀和(O(n²))
目的:O(1)计算任意列、任意行区间[i,j]的和,避免重复求和。
-
定义col_sum[r][c]:第c列前r行的和(1下标,方便计算);
-
递推:col_sum[r][c] = col_sum[r-1][c] + a[r-1][c-1](a为原矩阵,0下标);
-
列和计算:第c列[i,j]行和 = col_sum[j][c] - col_sum[i-1][c]。
Step 2:枚举上下边界(核心)
上边界i从1到n,下边界j从i到n(保证有效区间),枚举所有行区间[i,j],组合数为n(n+1)/2。
Step 3:压缩为一维数组
对每一组[i,j],构建arr数组(长度n),arr[c] = 第c+1列[i,j]行的和(通过col_sum计算)。
Step 4:每组合跑一次Kadane(核心)
用滚动DP优化的Kadane算法,O(n)求arr的最大子段和,即当前[i,j]下的最优子矩阵和,同步更新全局最大值。
三、完整干货代码
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;
// 枚举上下界 + 每组合跑Kadane,二维最大子矩阵和
int max_submatrix_sum(const vector<vector<int>>& a, int n) {
// 预处理列前缀和
vector<vector<int>> col_sum(n+1, vector<int>(n+1, 0));
for (int c = 1; c <= n; ++c) {
for (int r = 1; r <= n; ++r) {
col_sum[r][c] = col_sum[r-1][c] + a[r-1][c-1];
}
}
int ans = INT_MIN;
// 枚举所有上下边界组合
for (int i = 1; i <= n; ++i) { // 上边界
for (int j = i; j <= n; ++j) { // 下边界
// 压缩列和为一维数组
vector<int> arr(n);
for (int c = 0; c < n; ++c) {
arr[c] = col_sum[j][c+1] - col_sum[i-1][c+1];
}
// 对当前arr跑Kadane
int current = arr[0], max_sub = arr[0];
for (int c = 1; c < n; ++c) {
current = max(arr[c], current + arr[c]);
max_sub = max(max_sub, current);
}
// 更新全局最大值
ans = max(ans, max_sub);
}
}
return ans;
}
// 测试用例
int main() {
vector<vector<int>> a = {{1,-2,3},{4,-5,6},{7,-8,9}};
cout << max_submatrix_sum(a, 3) << endl; // 输出18
return 0;
}
四、高频易错点(避坑必看)
-
col_sum与原矩阵下标转换:col_sum是1下标,a是0下标,需注意r-1、c-1;
-
全局最大值ans初始化为INT_MIN,而非0(应对全负矩阵);
-
Kadane初始化:current和max_sub必须设为arr[0],不能为0;
-
上下边界枚举:j必须≥i,不遗漏i=j(单行)和j=n(最后一行)。
五、核心总结(必背)
1. 核心:枚举上下界→压缩一维→每组合跑Kadane;
2. 复杂度:O(n³),n≤100完全适用;
3. 关键:列前缀和提速,Kadane滚动DP省空间。

1354

被折叠的 条评论
为什么被折叠?



