蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)

这篇具有很好参考价值的文章主要介绍了蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目来源:最大子矩阵 - 蓝桥云课 (lanqiao.cn)

问题描述

小明有一个大小为 N×M 的矩阵, 可以理解为一个 N 行 M 列的二维数组。

我们定义一个矩阵 m 的稳定度 f(m) 为f(m)=max(m)−min(m), 其中 max(m) 表示矩阵 m 中的最大值, min(m) 表示矩阵 m 中的最小值。

现在小明想要从这个矩阵中找到一个稳定度不大于 limit 的子矩阵, 同时他还希望这个子矩阵的面积越大越好 (面积可以理解为矩阵中元素个数)。

子矩阵定义如下: 从原矩阵中选择一组连续的行和一组连续的列, 这些行列交点上的元素组成的矩阵即为一个子矩阵。

输入格式

第一行输入两个整数 N,M, 表示矩阵的大小

接下来 N 行, 侮行输入 M 个整数,表示这个矩阵

最后一行输入一个整数 limit, 表示限制

辎出格式

输出一个整数. 分别表示小明选择的子矩阵的最大面积

样例输入

3 4
2 0 7 9
0 6 9 7
8 4 6 4
8

样例输出

6

样例说明

满足稳定度不大于 8 的且面积最大的子矩阵总共有三个, 他们的面积都是 6 (粗体表示子矩阵元素)

2 0 7 9

0 6 9 7

8 4 6 4             

2 0 7 9

0 6 9 7

8 4 6 4

2 0 7 9

6 9 7

4 6 4

评测用例规模与约定

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)

对于所有评测用例, 0≤0≤ 矩阵元素值, limit ≤105≤105 。

题目大意

给定一个N*M的二维矩阵和一个数字limlit,求出符合稳定度f(m)<=limit面积最大的子矩阵
f(m)为当前子矩阵的最大值-最小值

解法一:暴力法(通过30%)

        通过四重循环(四条边)枚举每个子矩阵,然后再计算当前子矩阵的最大值和最小值之差,若差值满足<=limit,则维护更新面积最大值。
算法复杂度大于O(n^4)

解法二: 尺取法+单调队列(通过100%)

解题关键(三问):

1、如何较为快速地确定当前子矩阵的大小?

双指针算法(尺取法)

【图解】尺取法 

1、一开始左右指针都是从左端点开始 

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列) 

 2、右指针先向右移动

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列) 

3、右指针移动到刚好满足f(m)<=limit 的临界位置

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列) 

4、右指针再向右移动,这时候在区间[l, r']就不满足 f(m)<=limit 

 蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)

5、此时开始移动左指针 

 蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)

6、当左指针移动到刚好满足f(m)<=limit 的临界位置时,右指针开始移动,这样周而复始,直到右指针达到终点。

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列) 

 文章来源地址https://www.toymoban.com/news/detail-415617.html

        观察数据,可发现行的数据范围较小,列的数据范围较大,因此子矩阵的上下边可以通二.重遍历确定,复杂度,子矩阵的左右边采用双指针算法进行确定,复杂度。
算法复杂度

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)  

2、如何较为快速地找出当前子矩阵的两个最值?

        每次移动左右指针,都会后一整列的数字进入或退出当前子矩阵,我们需要先计算出当前列[up,down]范围的最值优化:通过转置矩阵,我们可以利用切片的方式,不用循环求出原矩阵每一列[up,down]范围内的最值

蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)  

3、当前子矩阵实在不断移动的,如何在移动过程中维护最值?

        使用两个队列分别记录当前子矩阵的最大值和最小值,维护队列的单调性,双指针移动过程中时刻更新队列。

单调队列

维护最大值的单调队列示例:

         第一个数字直接加入队列,后面每一列如果出现的数字比队列最后一个元素小,则加入队列,否则去掉队列最后一个元素, 再与队列最后一个比较,直到队列为空或者该数字比队列最后一个元素小再将该数字加入队列。
蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)

 

维护最大值的单调队列,内部元素是递减排列的

维护最小值的单调队列,内部元素是递增排列的

解题思路:双指针+单调队列

1、二重循环对矩阵的上下边界进行遍历
2、对于每个确定的上下边界up,down,左右边界采用双指针算法确定

3、使用两个队列分别记录当前子矩阵的最大值和最小值,维护队列的单调性,双指针移动过程中时刻更新队列
4、初始res=0保存结果,双指针移动过程中维护最大值

代码演示

from collections import deque
n, m = map(int, input().split())
mat = [list(map(int, input().split())) for _ in range(n)]   # 二维列表存矩阵:n行m列
lim = int(input())
max_res = 0

# 转置矩阵    m行n列  
remat = [[0] * n for _ in range(m)]
for i in range(m):                                          
    for j in range(n):
        remat[i][j] = mat[j][i]

for up in range(n):                # 两个for循环遍历上下边
    for down in range(up, n):
        l = 0    # 左指针初始化
        maxq = deque() # 最大值的单调队列
        minq = deque() # 最小值的单调队列
        #maxq.append(max(remat[l][up: down + 1]))    
        #minq.append(min(remat[l][up: down + 1]))
        for r in range(0, m):
            newmax = max(remat[r][up: down + 1])  # 右边新的一列l:[up,down]最大值
            while len(maxq) and maxq[-1] < newmax:# 最大值的单调队列的最后一个比新的最大值小
                maxq.pop()                        # 删除队列最后一个
            maxq.append(newmax)                   # 把新的一列的最大值放入队列
            newmin = min(remat[r][up: down + 1])  
            while len(minq) and minq[-1] > newmin:
                minq.pop()
            minq.append(newmin)
            cumax, cumin = maxq[0], minq[0]       # 子矩阵的最大值和最小值
            while cumax - cumin > lim and l < r:  # 最大-最小>lim,左指针<右指针
                if len(maxq) and max(remat[l][up: down + 1]) == maxq[0]: # 最左边的一列的最大值是子矩阵的最大值
                    maxq.popleft()                                       # 删除最大值,因为左指针要向右移动
                if len(minq) and min(remat[l][up: down + 1]) == minq[0]:
                    minq.popleft()
                cumax, cumin = maxq[0], minq[0]        #  更新子矩阵的最大值和最小值
                l += 1                                 #  左指针要向右移动
            if cumax - cumin > lim:                    # 特判:如果l=r且最大-最小>lim
                continue    
            cu_square = (r - l + 1) * (down - up + 1)  # 计算面积
            max_res = max(max_res, cu_square)
print(max_res)

 

 

 

 

 

到了这里,关于蓝桥杯刷题016——最大子矩阵(尺取法+单调队列)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 蓝桥杯刷题第二十三天

    题目描述 小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。 小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。 这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小

    2023年04月22日
    浏览(33)
  • 蓝桥杯刷题014——求阶乘(二分法)

    蓝桥杯2022省赛题目 问题描述 满足 N ! 的末尾恰好有  K 个 0 的最小的 N 是多少? 如果这样的 N 不存在输出 −1 。 输入格式 一个整数 K 。 输出格式 一个整数代表答案。 样例输入 样例输出 评测用例规模与约定 对于 30% 的数据, 1≤K≤10^6. 对于 100% 的数据, 1≤K≤10^

    2023年04月12日
    浏览(24)
  • 蓝桥杯刷题015——最少刷题数(二分法+前缀和)

    问题描述 小蓝老师教的编程课有  N 名学生 , 编号依次是 1…N  。 第 i 号学生这学期刷题的数量是 Ai​  。 对于每一名学生, 请你计算他 至少 还要再刷多少道题 , 才能使得 全班刷题比他多的学生数不超过刷题比他少的学生数。 输入格式 第一行包含一个正整数 N 。 第二

    2023年04月14日
    浏览(30)
  • 蓝桥杯刷题冲刺 | 倒计时6天

    作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 题目 链接: 4941. 凑数 - AcWing题库 初始时,n=0。 每一轮操作都要依次完成两个步骤: 第一步,任选一个 非负 整数 a,将 n 增加 a,这一步所需付出的代价为 a。 第二

    2023年04月08日
    浏览(32)
  • 蓝桥杯刷题冲刺 | 倒计时2天

    作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 题目 链接: 854. Floyd求最短路 - AcWing题库 给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,边权可能为负数。 再给定 k 个询问,每个询问包含两个整数

    2023年04月10日
    浏览(33)
  • 蓝桥杯刷题冲刺 | 倒计时3天

    作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 题目 链接: 790. 数的三次方根 - AcWing题库 给定一个浮点数 n,求它的三次方根。 输入格式 共一行,包含一个浮点数 n。 输出格式 共一行,包含一个浮点数,表示问

    2023年04月09日
    浏览(34)
  • 蓝桥杯刷题冲刺 | 倒计时1天

    作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾蓝桥杯加油,大家一定可以🐾 我是菜菜,最近容易我犯的错误总结 + 一些tips 各位蓝桥杯加油加油 当输入输出数据不超过 1e6 时, scanf printf 和 cin cout 是没有差距的; 超过这个数据范围时,就是用 scanf printf 多次调式,自己手

    2023年04月09日
    浏览(28)
  • 【蓝桥杯刷题冲刺辅导】掌握递归·DFS解题套路,这一文足以?

    大家好,我是安然无虞。 目录 一、刷题前和铁汁们唠一唠 1.刷题前须知 2.刷题时套路 1套路 2背下列常用数 ​ 3投机取巧:根据数据范围确定算法 ​ 4珍惜每分每秒 · 直接复制粘贴  5输入输出函数的使用 二、刷题强化 例一:递归实现指数型枚举 例二:递归实现排列型枚举

    2023年04月10日
    浏览(27)
  • 蓝桥杯每日一题----单调栈和单调队列

    单调栈即栈内的元素是单调递减或者单调递增的,我们通过一个题目来理解。 单调栈模板题 题目描述 给出项数为 n 的整数数列 a 1 … a n a_1…a_n a 1 ​ … a n ​ 。 定义函数 f ( i ) f(i) f ( i ) 代表数列中第 i 个元素之后第一个大于 a i a_i a i ​ 的元素的下标,即 f ( i ) = m i n i

    2024年02月19日
    浏览(28)
  • 单调队列-滑动窗口最大值

    Problem: 239. 滑动窗口最大值 输入一个数组nums,滑动窗口k遍历该数组,输出得到的最大值数组; 示例1: 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 构造一个单调队列表示当前窗口中单调递减的队列,队列的头就是最大值,为保证这个队列是窗口数据的表示,每次判断队

    2024年02月22日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包