题目:

链接: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 的最大数值和(利用前缀和转化为最大子序和问题)的更多相关文章

  1. Java实现 LeetCode 363 矩形区域不超过 K 的最大数值和

    363. 矩形区域不超过 K 的最大数值和 给定一个非空二维矩阵 matrix 和一个整数 k,找到这个矩阵内部不大于 k 的最大矩形和. 示例: 输入: matrix = [[1,0,1],[0,- ...

  2. Leetcode 363.矩形区域不超过k的最大数值和

    矩形区域不超过k的最大数值和 给定一个非空二维矩阵 matrix 和一个整数 k,找到这个矩阵内部不大于 k 的最大矩形和. 示例: 输入: matrix = [[1,0,1],[0,-2,3]], ...

  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 ...

  4. 【JavaScript】Leetcode每日一题-矩形区域不超过K的最大值和

    [JavaScript]Leetcode每日一题-矩形区域不超过K的最大值和 [题目描述] 给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大 ...

  5. [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 ...

  6. [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 ...

  7. BC 2015在百度之星程序设计大赛 - 预赛(1)(矩形区域-旋转卡)

    矩形区域 Accepts: 717 Submissions: 1619 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 ...

  8. C#窗口矩形区域着色

    C#写的一个GUI窗口,有几百个矩形区域.每个矩形区域的颜色随时都可能改变,并且多次改变. 我放弃使用label绘制矩形,因为效果不好.拖控件的界面使用power packs中的rectanglesh ...

  9. hiho #1502:最大子矩阵(元素和不超过k)

    #1502 : 最大子矩阵 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,并且该 ...

随机推荐

  1. Escape(反思与总结)

    题目描述: BH is in a maze,the maze is a matrix,he wants to escape! Input: The input consists of multiple ...

  2. std::sort为什么保证严格弱序?

    这个问题是面试腾讯光子的时候面试官提的,当时的问题是:sort自定义comp函数能用>=吗?当时的我想comp函数只要函数签名是对的应该就没问题吧,于是答了可以.面试结束后总感觉哪里不对,耿耿于 ...

  3. 【python数据挖掘】使用词云分析来分析豆瓣影评数据

    概述: 制作词云的步骤: 1.从文件中读取数据 2.根据数据追加在一个字符串里面,然后用jieba分词器将评论分开 3.设置WordCloud词云参数 4.保存最后的结果 数据:使用爬取的豆瓣影评数据 ...

  4. 在Oracle中使用sqlload做数据迁移

    前提:检查sqlload是否可用,输入sqlldr,提示有版本即可   1.创建测试表(已有则跳过)create table testTable(user varchar2(255),name var ...

  5. 洛谷题解 P1292 【倒酒】

    原题传送门 题目描述 Winy是一家酒吧的老板,他的酒吧提供两种体积的啤酒,a ml和b ml,分别使用容积为a ml和b ml的酒杯来装载. 酒吧的生意并不好.Winy发现酒鬼们都非常穷.有时,他们 ...

  6. 全栈之路-小程序API-SpringBoot项目中参数校验机制与LomBok工具集使用

    参数校验机制在web开发中是非常重要的,每当看到现在所在公司的校验代码,我都有头疼,每一个接口都是重新写参数的校验,有些复杂的接口,参数的校验甚至占了整个接口代码量的挺大一部分的,看着我都有些头疼,我 ...

  7. PHP0021:PHP COOKIE 设置修改删除

  8. 一起学Vue之条件判断

    在Vue进行前端开发中,条件判断主要用于根据不同的条件来决定显示或隐藏,或者进行视图之间的切换,本文以一个简单的小例子简述v-if的常见用法,仅供学习分享使用,如有不足之处,还请指正. v-if 指令 ...

  9. 小白的linux笔记2:关于进程的基本操作

    1.ps命令查看进程.ps -aux查看所有进程.可以用grep提取相关的部分进程,如只看python有关的:ps -aux |grep python. 进程状态:R运行中,T暂停,S休眠静止. 和进 ...

  10. 第3章 关系数据库标准语言SQL(重点) | 数据库知识点整理

    第3章 关系数据库标准语言SQL(重点) 了解 SQL语言发展过程 关系数据库技术和关系数据库管理系统RDBMS产品的发展过程 掌握 SQL语言的特点和优点 面向过程的语言和SQL语言的区别 关系数据 ...