363. 矩形区域不超过 K 的最大数值和(利用前缀和转化为最大子序和问题)
题目:
链接:https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/
给定一个非空二维矩阵 matrix 和一个整数 k,找到这个矩阵内部不大于 k 的最大矩形和。
示例:
输入: matrix = [[1,0,1],[0,-2,3]], k = 2
输出: 2
解释: 矩形区域 [[0, 1], [-2, 3]] 的数值和是 2,且 2 是不超过 k 的最大数字(k = 2)。
说明:
矩阵内的矩形区域面积必须大于 0。
如果行数远大于列数,你将如何解答呢?
解答:
太难了,看题解做的。
思路来自于最大子序和的题目。
暴力法想一下,如果要遍历所有可能的矩形,几乎是不可能的,而且有大量重复运算。
正确的方法是:利用前缀和。对于每一行的元素,先保存前缀和,即先计算一个二维数组prefix,prefix[i][j]表示:第i行前j个元素的和。
这样计算完了之后,取第i行[x1,x2]的元素和的话,只要计算prefix[i][x2]-prefix[i][x1-1]就可以了。
一个矩形不止左右的边,还有上下的边。所以上下的边我们也用这个方法。对于左右边界固定的矩形(假设为le,ri),矩形内每一行的元素和(其行号为row)为prefix[row][ri]-prefix[row][le-1];
竖向从上往下看,把矩形的每一行的元素和想象成一个元素,一共有row-1行,相当于一个一维数组。这时候问题就变成了最大子序和。
至于为什么先固定左右边界,上下方向调用最大子序和算法,而不是反过来。是因为题目给了条件:行数远大于列数。
假设行数row,列数col,我们的算法复杂度应该是:O(col^2*row*logrow),因为外层两个for循环是col*col。内部set最大查询复杂度row*log row。
如果先固定上下边界,再左右方向调用最大子序和算法的话:复杂度就是:O(row^2*col*logcol),显然row远大于col的时候,row^2太大了,时间效率不如前者。
代码:
class Solution {
public:
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
if(matrix.empty() or matrix[].empty()){return ;}
int R=matrix.size(),C=matrix[].size();
vector<vector<int>> prefix(R+,vector<int>(C+,));
for(int i=;i<=R;++i){prefix[i][]=matrix[i-][];}
for(int i=;i<=R;++i){
for(int j=;j<=C;++j){
prefix[i][j]=prefix[i][j-]+matrix[i-][j-];
}
}
int res=INT_MIN;
for(int le=;le<=C;++le){
for(int ri=le;ri<=C;++ri){
//矩形左右边界为[le-1,ri-1],下面考察所有可能上下边界
set<int> area={};
int pre_area=;
for(int i=;i<=R;++i){
int cur_area=prefix[i][ri]-prefix[i][le-]+pre_area;
auto iter=lower_bound(area.begin(),area.end(),cur_area-k);
if(iter!=area.end()){res=max(res,cur_area-*iter);}
area.insert(cur_area);
pre_area=cur_area;
}
}
}
return res;
}
};
除了变量名基本全一样的代码,别人能跑400ms,我就一脸懵逼了。找了半天,发现了:
人家是set容器直接调用lower_bound成员函数,我调用的是stl库的lower_bound函数。
改为:set自带的lower_bound,空间大家都一样,但时间大大缩短:

难以置信这两个函数居然效率差这么多,然后去百度,贴一个解释:

原因是:stl的lower_bound是二分查找,需要用到随机存取的特性。
但set是红黑树,非线性结构,迭代器是无法随机存取的。
比如这个代码是错的:
int main()
{
set<int> p={,,,,,,,};
cout<<*(p.begin()+);
getchar();
return ;
}
那既然不能随机存取,对set的[le,ri]区间进行二分查找的复杂度也就肯定不止logN了。
所以容器如果自带lower_bound函数,包括其他函数也是一样,如果容器自己实现了相应的函数,应该优先调用。
用vector替代set也可以,lower_bound本身就是二分,set内部是红黑树。二者查询指定数据的复杂度都是O(n logn),但这道题来说,vector快一些,因为数据比较大的时候,set建立红黑树比较费时。
用vector的版本:
class Solution {
public:
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
if(matrix.empty() or matrix[].empty()){return ;}
int R=matrix.size(),C=matrix[].size();
vector<vector<int>> prefix(R+,vector<int>(C+,));
for(int i=;i<=R;++i){prefix[i][]=matrix[i-][];}
for(int i=;i<=R;++i){
for(int j=;j<=C;++j){
prefix[i][j]=prefix[i][j-]+matrix[i-][j-];
}
}
int res=INT_MIN;
for(int le=;le<=C;++le){
for(int ri=le;ri<=C;++ri){
//矩形左右边界为[le-1,ri-1],下面考察所有可能上下边界
vector<int> area={};
int pre_area=;
for(int i=;i<=R;++i){
int cur_area=prefix[i][ri]-prefix[i][le-]+pre_area;
auto iter=lower_bound(area.begin(),area.end(),cur_area-k);
if(iter!=area.end()){res=max(res,cur_area-*iter);}
area.insert(lower_bound(area.begin(),area.end(),cur_area),cur_area);
pre_area=cur_area;
}
}
}
return res;
}
};

363. 矩形区域不超过 K 的最大数值和(利用前缀和转化为最大子序和问题)的更多相关文章
- Java实现 LeetCode 363 矩形区域不超过 K 的最大数值和
363. 矩形区域不超过 K 的最大数值和 给定一个非空二维矩阵 matrix 和一个整数 k,找到这个矩阵内部不大于 k 的最大矩形和. 示例: 输入: matrix = [[1,0,1],[0,- ...
- Leetcode 363.矩形区域不超过k的最大数值和
矩形区域不超过k的最大数值和 给定一个非空二维矩阵 matrix 和一个整数 k,找到这个矩阵内部不大于 k 的最大矩形和. 示例: 输入: matrix = [[1,0,1],[0,-2,3]], ...
- [Swift]LeetCode363. 矩形区域不超过 K 的最大数值和 | Max Sum of Rectangle No Larger Than K
Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix s ...
- 【JavaScript】Leetcode每日一题-矩形区域不超过K的最大值和
[JavaScript]Leetcode每日一题-矩形区域不超过K的最大值和 [题目描述] 给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大 ...
- [LeetCode] 363. Max Sum of Rectangle No Larger Than K 最大矩阵和不超过K
Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix s ...
- [LeetCode] Max Sum of Rectangle No Larger Than K 最大矩阵和不超过K
Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix s ...
- BC 2015在百度之星程序设计大赛 - 预赛(1)(矩形区域-旋转卡)
矩形区域 Accepts: 717 Submissions: 1619 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 ...
- C#窗口矩形区域着色
C#写的一个GUI窗口,有几百个矩形区域.每个矩形区域的颜色随时都可能改变,并且多次改变. 我放弃使用label绘制矩形,因为效果不好.拖控件的界面使用power packs中的rectanglesh ...
- hiho #1502:最大子矩阵(元素和不超过k)
#1502 : 最大子矩阵 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,并且该 ...
随机推荐
- MATLAB中冒号的用法解析
MATLAB中冒号的用法解析 1.: 表示所有的意思. (1)如:a(1,:) 表示a的第1行,示例: 结果: 同样的如果a(2,:)表示a的第2行 (2)反过来,a(:,2) 表示a的第3列,示例: ...
- visual studio 2019:error c2760
笔者在敲书上的练习题时(完全按照书上代码,没有语法错误),报"error c2760"错误. 代码出错位置(代码并没有问题): 在网上查找了一下,发现"c2760&quo ...
- Android中获取目标布局文件中的组件
方法如下: LayoutInflater flater= LayoutInflater.from(getContext()); //R.layout.title处填写目标布局 final View v ...
- Redis的启动和关闭(前台启动和后台启动)
场景 Centos中Redis的下载编译与安装(超详细): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 在上 ...
- 【DTOJ】2703:两个数的余数和商
DTOJ 2703:两个数的余数和商 解题报告 2017.11.10 第一版 ——由翱翔的逗比w原创,引用<C++ Primer Plus(第6版)中文版> 题目信息: 题目描述 给你a ...
- nodejs 使用 body-parser 获取网页内容
var bodyParser = require('body-parser'); var urlencodedParser = bodyParser.urlencoded({ extended: fa ...
- JS中0.1+0.2!=0.3
在控制台输入0.1+0.2,会得出以下结果 即不等于0.3.下面我们说一下原因. 一.存储原理 1.在计算机中数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的.2.在JS中数字采用的IEEE ...
- es5和es6中如何处理不确定参数
场景:求出不定参数的总数和 //利用arguments function sum () { let num = 0 //Array.prototype.forEach.call(arguments,f ...
- Upx 压缩go编译的程序 frp
1. frp 程序占用大 .路由器 不够空间 2. UPX 下载地址 https://github.com/upx/upx/releases/ 3. 压缩命令 upx.exe -9 C ...
- 纪中21日T3 2118. 【2016-12-30普及组模拟】最大公约数
纪中21日T3 2118. 最大公约数 (File IO): input:gcd.in output:gcd.out 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 Goto ...
