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希望你能求出其中最大(元素数目最多)的子矩阵,并且该 ...
随机推荐
- Vue中使用NProgress实现进度条
简介 NProgress是页面跳转或者发生异步请求是浏览器顶部的进度条 GitHub地址:https://github.com/rstacruz/nprogress 在线演示地址:http://ric ...
- AMBA简介
AMBA AMBA(Advanced Microcontroller Bus Architecture)先进的微控制器总线架构是一个免费.开放的标准,用于SoC内部功能模块之间的互连和管理.对成功设计 ...
- tomcat虚拟路径的配置方法
方式一: 将web项目配置到webapps以外的目录 在conf/server.xml中配置,找到<host>标签,<Content docBase="E:\yqs\Jsp ...
- 全网小说免费阅读下载APP
先说主题:今天分享一个全网小说免费阅读下载APP.这篇文章是凌晨2点钟写的,原因呢可能有两点: 半夜无眠,一时兴起就想分享点有用的东西给大家,就问你感动不?其实吧,可能是晚上喝了点儿浓茶导致的无眠,所 ...
- 剑指offer-面试题42-连续子数组的最大和-动态规划
/*题目; 输入一个整形数组(可能有正数和负数),求数组中连续子数组(最少有一个元素)的最大和. 要求时间复杂度为O(n). 先输入数组的格式,再依次输入数组的值.*//*思路: f(i) = pDa ...
- 通俗易懂的RESTful API实践详解(含代码)
来源:点击进入 点击上方链接,版面更好 一.什么是RESTful REST 是面向资源的,这个概念非常重要,而资源是通过 URI 进行暴露,URI 的设计只要负责把资源通过合理方式暴露出来就可以了,对 ...
- CF 150E Freezing with Style [长链剖分,线段树]
\(sol:\) 给一种大常数 \(n \log^2 n\) 的做法 考虑二分,由于是中位数,我们就二分这个中位数,\(x>=mid\)则设为 \(1\),否则为 \(-1\) 所以我们只需要找 ...
- C# 将List数据 导出到csv 文件
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Ref ...
- 报错:无法加载文件 D:\nodejs\node_global\webpack.ps1,因为在此系统上禁止运行脚本...
解决报错:(1)以管理员身份运行vs code (2)在终端执行:get-ExecutionPolicy,显示Restricted(表示状态是禁止的) [受限制的.保密的] (3)在终端执行:set ...
- 2-1.了解Pod对象
1.Pod参数定义 # 必填,版本号 apiVersion: string kind: Pod # 必填,元数据 metadata: # 必填,Pod对象的名称(命名规范需要符合RFC 1035规范) ...
