题目:

链接: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. cf1294E

    题意简述:给一个矩阵,有两种操作可以进行 操作1:改变矩阵中一个元素的值 操作2:将矩阵中某一列的值循环下移 要求用最少的操作次数使得矩阵变成 题解:对于一列来说,我们肯定是先变化然后再循环下移,所以 ...

  2. 用Python制作酷炫词云图,原来这么简单!

    一.简介词云图是文本挖掘中用来表征词频的数据可视化图像,通过它可以很直观地展现文本数据中地高频词:! 图1 词云图示例 在Python中有很多可视化框架可以用来制作词云图,如pyecharts,但这些 ...

  3. VBA-FileToFileUpdate

    Public Sub FileToFileUpdate(ByVal fileName As String, ByVal strFrm As String, ByVal strTo As String) ...

  4. hadoop学习摘要

    参考链接:https://www.zhihu.com/question/333417513 https://www.oschina.net/p/hbase hadoop环境搭建:https://blo ...

  5. scanf 与fgets

    scanf: 1.以输入字符串也可以输入数字 . 2.遇到空格就停止.3.会有segmentation fault. fgets: 1.只能输入字符串.2.回车才会停止.3.不会有segmenntat ...

  6. java面试必问问题总结

    1. 自我介绍 2. get跟load的区别 3. 什么是重载,什么是重写 4. HashTable跟HashMap的区别 5. Jsp九大隐式对象 6. Forword和redirect 的区别 7 ...

  7. 【Android】LitePal的基础

    一.环境配置 LitePal 在GitHub地址为:https://github.com/LitePalFramework/LitePal 我们使用起来也很方便,直接在gradle中配置即可. 如果你 ...

  8. 今日份Java

    package util; import java.sql.*; public class DBUtil { static String url = "jdbc:mysql://localh ...

  9. git同步代码至github和gitee(码云)

    注:本文出自博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 本文源链接:https://www.cnblogs.com/chloneda/p/git-to-g ...

  10. jquery form表单赋值封装

    ;!(function ($) { $.fn.setFormValue = function (options) { var $this = $(this); $.each(options, func ...