基础知识点
C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例
题目
给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大数值和。
 题目数据保证总会存在一个数值和不超过 k 的矩形区域。
 示例 1:
 输入:matrix = [[1,0,1],[0,-2,3]], k = 2
 输出:2
 解释:蓝色边框圈出来的矩形区域 [[0, 1], [-2, 3]] 的数值和是 2,且 2 是不超过 k 的最大数字(k = 2)。
 示例 2:
 输入:matrix = [[2,2,-1]], k = 3
 输出:3
提示:
 m == matrix.length
 n == matrix[i].length
 1 <= m, n <= 100
 -100 <= matrix[i][j] <= 100
 -105 <= k <= 105
分析
二维前缀和
vPreSum[r][c] 记录以(0,0)开始,宽高为c r的矩形和。vPreSum[r][c] = vPreSum[r - 1][c] + vPreSum[r][c - 1] + matrix[r - 1][c - 1] - vPreSum[r - 1][c - 1];
 
| vPreSum[r - 1][c] | 绿色实心矩形的和 | 
| vPreSum[r][c - 1] | 蓝色空心矩形 | 
| matrix[r - 1][c - 1] | 黄色矩形 | 
| vPreSum[r - 1][c - 1] | 蓝绿重叠部分 | 
时间复杂度O(nnn*logn)
枚举所有矩形,时间复杂度是O(n^4),超时。三层循环,第一层和第二层循环,枚举左右。第三层循环枚举下,setSum记录了所有合法的t的构成的矩形(left,0,right,t-1)的和。显然iLeftRight - setSum任意元素的值,就是(left,t,right,row)矩形的和。iLeftRight 是矩形(left,0,right,row)的和。对setSum 进行二分。
源码
class Solution {
 public:
 int maxSumSubmatrix(vector<vector>& matrix, int k) {
 m_r = matrix.size();
 m_c = matrix.front().size();
 vector<vector> vPreSum(m_r+1,vector(m_c+1,0)); //vPreSum[r][c] 以(0,0)开始,宽高为c r的矩形
 for (int r = 1; r <= m_r; r++)
 {
 for (int c = 1; c <= m_c; c++)
 {
 //令r=1,c=1 vPreSum[1][1] = 0 +0 + matrix[0][0] -0
 //令r=2,c=2 vPreSum[2][2] = vPreSum[1][2] +vPreSum[2][1] + matrix[1][1] + vPreSum[1][1]
 vPreSum[r][c] = vPreSum[r - 1][c] + vPreSum[r][c - 1] + matrix[r - 1][c - 1] - vPreSum[r - 1][c - 1];
 }
 }
 int iMin = INT_MIN;
 //vector<vector> vDebug(m_r, vector(m_c,INT_MIN));
 for (int left = 0; left < m_c ; left++ )
 {
 for (int right = left ; right < m_c; right++ )
 {
 //row和right 是右下角的坐标
 set setSum = { 0 };
 for (int row = 0; row < m_r; row++)
 {
 const int iLeftRight = vPreSum[row + 1][right + 1]
- vPreSum[row + 1][left];
 //iLeftRight - x <=k ==> -x <= k - iLeftRight ==> x >= iLeftRight-k
 auto it = setSum.lower_bound(iLeftRight - k);
 if (setSum.end() != it)
 {
 iMin = max(iMin, iLeftRight - *it);
 //vDebug[row][right] = iLeftRight - *it;
 }
 setSum.emplace(iLeftRight);
 }
 }
 }
 return iMin;
 }
 int m_r, m_c;
 };
测试用例
template
 void Assert(const vector& v1, const vector& v2)
 {
 if (v1.size() != v2.size())
 {
 assert(false);
 return;
 }
 for (int i = 0; i < v1.size(); i++)
 {
 assert(v1[i] == v2[i]);
 }
 }
template
 void Assert(const T& t1, const T& t2)
 {
 assert(t1 == t2);
 }
 int main()
 {
 vector<vector> matrix = { {1, 2, 3}, { 4,5,6 } };
 int k = 2;
 auto res = Solution().maxSumSubmatrix(matrix, k);
 Assert(res, 2);
 matrix = { {1, 0, 1}, { 0,-2,3 } };
 k = 2;
 res = Solution().maxSumSubmatrix(matrix, k);
 Assert(res, 2);
 matrix = { {2,2,-1} };
 k = 3;
 res = Solution().maxSumSubmatrix(matrix, k);
 Assert(res, 3);
 CConsole::Out(res);
 }

扩展阅读
视频课程
有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
 https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
 https://edu.csdn.net/lecturer/6176
相关下载
想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
 https://download.csdn.net/download/he_zhidan/88348653
| 鄙人想对大家说的话 | 
|---|
| 闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 | 
| 墨家名称的来源:有所得以墨记之。 | 
| 如果程序是一条龙,那算法就是他的是睛 | 
测试环境
操作系统:win7 开发环境: VS2019 C++17
 或者 操作系统:win10 开发环境: VS2022 C++17
