算法第十二天-矩形区域不超过K的最大数值和

矩形区域不超过K的最大数值和

题目要求


解题思路

来自[宫水三叶]
从题面来看显然是一道[二维前缀和]的题目。本题预处理前缀和的复杂度为O(m* n)
搜索所有子矩阵需要枚举[矩形左上角]和[矩形右下角],复杂度是 O ( m 2 ∗ n 2 ) O(m^2 * n^2) O(m2n2),因此,如果把本题当作二维前缀和模板题来做的话,整体复杂度为 O ( m 2 ∗ n 2 ) O(m^2 * n^2) O(m2n2).
数据范围是 1 0 2 10^2 102,对应的计算量是 1 0 8 10^8 108,理论上会超时,但当我们枚举[矩形左上角](i,j)的时候,我们只需要搜索位于(i,j)的右下方的点(p,q)作为[矩形右下角],所以其实我们是取不满 m 2 ∗ n 2 m^2 * n^2 m2n2的,但是,仍然存在超时风险。

前缀和 & 二分(抽象一维)

我们来细想一下[朴素二维前缀和]解法是如何搜索答案(子矩阵):通过枚举[左上角] & [右下角]来确定某个矩阵
换句话说是通过枚举(i,j)和(p,q)来唯一确定子矩阵的四条边,每个坐标点可以看作确定子矩阵的某条边。
既然要确定的边有四条,我们如何降低复杂呢?
简单的,我们先思考一下同样是枚举的[两数之和]问题
在[两数之和]中可以暴力枚举两个数,也可以只枚举其中一个数,然后使用数据结构(哈希表)来加速找另一个数(这是一个通用的[降低枚举复杂度]思考方向)。
对应到本题,我们可以枚举其中三条边,然后使用数据结构来加速找第四条边。
当我们确定了三条边(红色)之后,形成的子矩阵就单纯取决于第四条边的位置(黄色):
在这里插入图片描述

于是问题转换为[如何快速求得第四条边(黄色)的位置在哪]。
我们可以进一步将问题缩小,考虑矩阵之有一行(一维)的情况:

这时候问题进一步转换为[在一维数组中,求解和不超过K的最大连续子数组之和]。
对于这个一维问题,我们可以先预处理出[前缀和],然后枚举子数组的左端点,然后通过[二分]来求解其右端点的位置。
假定我们已经求得一维数组的前缀和数组sum,即可得下标范围[i,j]的和为:
areaSum(i,j) = sum[j] - sum[i-1] <=k
经过变形后得:
sum[j] <= k + sum[i-1]
我们两种思路来最大化areaSum(i,j):

  • 确定(枚举)左端点位置i,求得符合条件的最大右端点sum[j]
  • 确定(枚举)右端点位置j,求得符合条件的最小左端点sum[i]
    对于没有负权值的一维数组,我们可以枚举左端点i,同时利用前缀和的[单调递增]特性,通过[二分]找到符合sum[j] <= k +sum[i-1]条件的最大值sum[j],从而求解出答案
    但是如果是含有负权值的话,前缀和将会丢失[单调递增]的特性,我们也就无法使用枚举i并结合[二分]查找j的做法。
    这时候需要将过程反过来处理:我们从左到右枚举j,并使用[有序集合]结构维护遍历过的位置,找到符合sun[j] - k <= sum[i] 条件最小值sum[i],从而求解出答案。
    基于上述分析,解决这样的一维数组问题复杂度是 O ( n l o g n ) O(n log n) O(nlogn)。将这样子思路应用到二维需要一点点抽象能力。
    同时,将一维思路引用到本题(二维),复杂度要么是 O ( m 2 ∗ n l o g n ) O(m ^2 * n logn) O(m2nlogn)要么是 O ( n 2 ∗ m l o g m ) O(n^2 * m log m) O(n2mlogm)
    我们先不考虑[最大化二分收益]问题,先假设我们是固定枚举[上下行]和[右边列],这时候唯一能够确定一个子矩阵则是取决于[左边列]:

重点是如何与[一维]问题进行关联:显然[目标子矩阵的和]等于[子矩阵的右边列 与 原矩阵的左边列 形成的子矩阵和] - [子矩阵左边列 与 原矩阵左边列 形成的子矩阵和]

我们可以使用area[r]代表[子矩阵的右边列 与 原矩阵的左边列 形成的子矩阵之和],使用area[l-1]代表[子矩阵的左边列 与 原矩阵的左边列 形成的子矩阵和]的话,则有:
target = area[r] - area[l-1] <=k
这与我们[一维问题]完全一直,同时由[上下行]&[右边列]可与直接确定area[r]的大小,通过[有序集合]存储我们遍历r过程中固定所有area[r]从而实现[二分]查找符合area[r] - k <= area[l-1]条件的最小area[l-1]
至此,我们通过预处理前缀和+容斥原理彻底将题目转换为[一维问题]进行来求解。

其他解法

首先有三个变量row,col,res第一个记录行,第二个记录列,第三个记录矩形和
然后看二维矩阵matrix,我们有两个索引left,right,这两个索引代表列与列之间的范围。
开始先从第0列开始,同时也作为左边的列left,然后再取右边的列right逐渐将右移。并且记录同一行左边的列与右边的列的和.
这里有个需要注意的,我们首先是取第0列作为左边的列,然后右边的列依次从第0列开始逐渐到最后一列,在此期间同一行的左右列会逐渐相加。当我们这次一整个循环完,左边的列会更新成1,也就是for left in range(col),然后重置新一轮的计算和,再继续循环右边的列。
接下来当我们累加和计算完之后就相当于将二维变成了一维,之后我们将在这个一维里面计算最大的矩形和。一个列表lst用来存放累加的和,一个变量cur用来累加之前算出来的累加列表sums。
我们这里需要找到的是最大的矩形和,但是有一个条件,那就是不大于k。比如我们要求sums(i,j)=sums(0,j)-sums(0,i-1)那么我们可以把sums(i,j)=k且不大于k,sums(0,j)-sums(0,i-1)<=k,可以写成sums(0,j)-k<=sums(0,i-1),我们可以看这个式子是否成立。
所以当我们累加和第一个值之后loc = bisect.bisect_left(lst,cur-k)可以看成sums(0,j)-k<=sums(0,i-1),接下来进行一个if判断,如果成立那么cur-lst[loc]可以看成sums(0,j)-sums(0,i-1)<=k计算出值,之后进行res最大值计算。

想不起来可以参看

https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/solution/javacong-bao-li-kai-shi-you-hua-pei-tu-pei-zhu-shi/

代码

class Solution:
    def maxSumSubmatrix(self, matrix: List[List[int]], k: int) -> int:
        import bisect
        row = len(matrix)
        col = len(matrix[0])
        res = float("-inf")
        for left in range(col):
            # 以left为左边界,每行的总和
            _sum = [0] * row
            for right in range(left, col):
                for j in range(row):
                    _sum[j] += matrix[j][right]
                # 在left,right为边界下的矩阵,求不超过K的最大数值和
                arr = [0]
                cur = 0
                for tmp in _sum:
                    cur += tmp
                    # 二分法
                    loc = bisect.bisect_left(arr, cur - k)
                    if loc < len(arr):res = max(cur - arr[loc], res)
                    # 把累加和加入
                    bisect.insort(arr, cur)
        return res

复杂度分析

时间复杂度: O ( m 2 ∗ n 2 ) O(m^2 * n^2 ) O(m2n2)
空间复杂度: O ( n ) O(n) O(n)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/297789.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何安装 Python

1.打开浏览器 输入网址 :www.python.org ​ 2.根据电脑系统配置进行下载 ​ 3.确定电脑系统属性&#xff0c;此处我们以win10的64位操作系统为例 ​ 4.安装python 3.6.3 双击下载的安装包 python-3.6.3.exe 注意要勾选&#xff1a;Add Python 3.6 to PATH 点击 Customize…

听GPT 讲Rust源代码--compiler(27)

File: rust/compiler/rustc_mir_build/src/build/expr/as_place.rs 在Rust编译器的源代码中&#xff0c;文件rust/compiler/rustc_mir_build/src/build/expr/as_place.rs的作用是用于处理表达式的转换为L-value的过程。L-value是指那些可接受赋值操作的表达式&#xff0c;如变量…

企业Aspera替代方案有哪些推荐

随着企业数据量的不断增加&#xff0c;数据传输和共享成为了一个重要的问题。Aspera是一款高性能、低延迟的数据传输工具&#xff0c;但是它并不是万能的&#xff0c;随着数据量的不断增大&#xff0c;也有一些企业需要寻找Aspera的替代方案。本文将介绍三种常用的企业Aspera替…

复旦MBA科创青干营(二期):探索合肥科创企业的创新之路

11月18日-19日&#xff0c;复旦MBA科创青干营二期学生开启了整合实践活动的第三次企业参访&#xff0c;前往位于合肥的蔚来第二先进制造基地、安徽万邦医药科技股份有限公司和合肥国轩高科动力能源有限公司&#xff0c;在学术导师和科创企业家“双导师”的指导下&#xff0c;深…

近屿智能OJAC带您从0到1全方位深度学习AI大模型,星辰大海和你开创!

Look&#xff01;&#x1f440;我们的大模型商业化落地产品&#x1f4d6;更多AI资讯请&#x1f449;&#x1f3fe;关注Free三天集训营助教在线为您火热答疑&#x1f469;&#x1f3fc;‍&#x1f3eb; 在这个信息爆炸的数字时代&#xff0c;你是否也想掌握那种像魔法一样的AI技…

Git - 强制替换覆盖 master 分支解决方案

问题描述 在版本迭代中&#xff0c;通常会保持一个主分支 master&#xff0c;及多个 dev 分支&#xff0c;但是因为 dev 分支的开发周期过长&#xff0c;迭代太多而没有及时维护 master &#xff0c;导致后来发版上线的大部分代码都在 dev 分支上&#xff0c;如果将代码在 mas…

【Python学习】Python学习4-运算符

目录 【Python学习】Python学习4-运算符 前言算术运算符比较&#xff08;关系&#xff09;运算符赋值运算符逻辑运算符位运算符成员运算符身份运算符运算符优先级参考 文章所属专区 Python学习 前言 本章节主要说明Python的运算符。主要有 算术运算符 比较&#xff08;关系&…

MYSQL - SQL优化

插入数据优化 小批量数据 批量插入 最好插入500-1000条比较好 手动提交事务 主键顺序插入 大批量插入数据 主键优化 页分裂 页合并 主键优化设计原则 order by优化 group by优化 limit优化 count优化 count(1)里面不一定必须1&#xff0c;数字都可以 update优化 更新字…

Ubuntu同步两个剪切板

众所周知&#xff0c;ubuntu系统中有两套剪切板。第一个剪切板是用鼠标操作&#xff0c;鼠标选中则复制&#xff0c;点击鼠标中键则粘贴&#xff08;这个剪切板通常叫做——选择缓冲区&#xff09;。第二个剪切板则是真正的剪切板&#xff0c;使用ctrlc&#xff08;在终端中默认…

响应式开发

响应式开发的原理Bootstrap前端开发框架Bootstrap栅格系统阿里百秀首页案例 响应式开发原理 1 响应式需要一个父级做为布局容器&#xff0c;来配合子级元素来实现变化效果。 2 在不同屏幕下&#xff0c;通过媒体查询来改变这个布局容器的大小&#xff0c;再改变里面子元素的排…

JDK 11:崭新特性解析

JDK 11&#xff1a;崭新特性解析 JDK 11&#xff1a;崭新特性解析1. HTTP Client&#xff08;标准化&#xff09;示例代码 2. 局部变量类型推断的扩展示例代码 3. 新的字符串方法示例代码 4. 动态类文件常量示例代码 5. Epsilon 垃圾收集器使用方式 结语 JDK 11&#xff1a;崭新…

LeetCode-有效的字母异位词(242)

题目描述&#xff1a; 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 思路&#xff1a; 这题还是比较简单的&#xff0c;首先将两个字符…

Transformer 的双向编码器表示 (BERT)

一、说明 本文介绍语言句法中&#xff0c;最可能的单词填空在self-attention的表现形式&#xff0c;以及内部原理的介绍。 二、关于本文概述 在我之前的博客中&#xff0c;我们研究了关于生成式预训练 Transformer 的完整概述&#xff0c;关于生成式预训练 Transformer (GPT) 的…

Mybatis分页插件PageHelper的配置和使用

文章目录 每页10条记录&#xff0c;取第一页&#xff0c;返回的是前10条记录每页10条记录&#xff0c;取第二页&#xff0c;返回的是第11条记录&#xff0c;到第20条记录&#xff0c; MySQL对分页的支持 简单来说MySQL对分页的支持是通过limit子句。请看下面的例子。 limit关键…

VCG 点到平面的投影点

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 假设给定的平面为 a x + b y + c z + 1 = 0 ax+by+cz+1=0

2024年【烟花爆竹经营单位主要负责人】考试题及烟花爆竹经营单位主要负责人考试资料

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【烟花爆竹经营单位主要负责人】考试题及烟花爆竹经营单位主要负责人考试资料&#xff0c;包含烟花爆竹经营单位主要负责人考试题答案和解析及烟花爆竹经营单位主要负责人考试资料练习。安全生产模拟考试一点通…

OpenCV-Python(25):Hough直线变换

目标 理解霍夫变换的概念学习如何在一张图片中检测直线学习函数cv2.HoughLines()和cv2.HoughLinesP() 原理 霍夫变换在检测各种形状的的技术中非常流行。如果你要检测的形状可以用数学表达式写出来&#xff0c;你就可以是使用霍夫变换检测它。即使检测的形状存在一点破坏或者…

【数据库】聊聊常见的索引优化-上

数据库对于现有互联网应用来说&#xff0c;其实是非常重要的后端存储组件&#xff0c;而大多数系统故障都是由于存储所导致的&#xff0c;而数据库是重中之重&#xff0c;所以为了比较好掌握SQL的基本优化手段&#xff0c;打算用两篇文章从基本的联合索引优化、group by/order …

【Kubernetes】认证授权RBAC (一)

认证授权RBAC 一、k8s安全管理&#xff1a;认证、授权、准入控制概述1.1、简介【1】认证基本介绍【2】授权基本介绍【3】准入控制基本介绍 1.2、认证【1】客户端认证【2】Bearertoken【3】Serviceaccount【4】拓展&#xff1a;kubeconfig文件 1.3、授权【1】什么是RBAC&#xf…

使用 Python 和 wxPython 在图片上添加水印

创建一个基于wxPython的简单水印生成器应用程序。该应用程序具有一个窗口&#xff0c;用户可以选择要添加水印的图片文件&#xff0c;并在输入框中输入要显示在图片底部的文字。点击"印章"按钮后&#xff0c;应用程序将在选择的图片上添加水印&#xff0c;并将生成的…