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希望你能求出其中最大(元素数目最多)的子矩阵,并且该 ...
随机推荐
- 从零开始一个个人博客 by asp.net core and angular(一)
这是一个个人叙述自己建设博客的帖子,既然是第一篇那肯定是不牵扯代码了,主要讲一下大体的东西,微软最新的web框架应该就数asp.net core 3.1了这是一个长期支持版,而且是跨平台又开源版本,所 ...
- vue使用JSEncrypt实现rsa加密及挂载方法
挂载全局方法 使用jsencrypt进行rsa加密 原文链接:Js参数RSA加密传输,jsencrypt.js的使用 - CSDN博客* https://blog.csdn.net/p31201115 ...
- 《手把手教你构建自己的 Linux 系统》学习笔记(8)
目录 Binutils 软件包有什么用? make -k 的作用是什么? man-pages 里有几种文档?分别表示什么意思? 如何查询指定目录的 man-pages ? 如何使用 make 命令的同 ...
- .net core 3.0配置跨域
1.ConfigureServices services.AddCors(c => { // 配置策略 c.AddPolicy("Policy", policy => ...
- Win10桌面菜单弹出cmd解决办法
现象 Win10右键菜单打开弹出命令提示符 原有个性化.显示设置.网络和Internet设置无法使用 解决 注册表定位到HKEY_CURRENT_USER\Software\Classes\ ms-s ...
- Sass环境安装-Sass sublime 编辑器插件编译方法
首先官网(http://www.ruby-lang.org/en/downloads/)下载 ruby (1)打开链接进入到下载页面,点击如下位置进行下载 (2)下载页面 (3)进入到各个版本的列表页 ...
- shell awk学习3
需求: 某文件aa的内容如下: a/p1/p2b/pp1c/ppp1/ppp3d/p1/p2/p3e/p1/p2/p3/p4 期望输出结果: a /p1 /p2 b /pp1 c /ppp1 /ppp ...
- TCP 协议快被淘汰了,UDP 协议才是新世代的未来?
TCP 协议可以说是今天互联网的基石,作为可靠的传输协议,在今天几乎所有的数据都会通过 TCP 协议传输,然而 TCP 在设计之初没有考虑到现今复杂的网络环境,当你在地铁上或者火车上被断断续续的网络折 ...
- php外挂python脚本抓取ajax数据
之前我写过一遍php外挂python脚本处理视频的文章.今天和大家分享下php外挂python实现输入关键字搜索的脚本 首先我们先来分析一波网站: http://www.dzdpw.com/s.php ...
- scrapy框架综合运用 爬取天气预报 + 定时任务
爬取目标网站: http://www.weather.com.cn/ 具体区域天气地址: http://www.weather.com.cn/weather1d/101280601.shtm(深圳) ...
