【LeetCode题解】矩形问题

本文详细解析了如何利用动态规划和单调栈解决LeetCode中的矩形问题,包括柱状图中最大矩形、二维数组最大矩形和接雨水问题。文章深入探讨了动态规划的应用,以及单调栈在降低时间复杂度中的作用,提供了多种解决方案和代码实现。
摘要由CSDN通过智能技术生成

矩形问题

一般使用动态规划,单调栈。

例题

柱状图中最大的矩形

84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

在这里插入图片描述
思路一
暴力解法,定义两个指针i,j,两个区间直接的面积就是:min(i…j) * (j-i+1),遍历两个指针的组合得到最大的面积数,这种解法的时间复杂度是On^2

代码

class Solution {
   
    public int largestRectangleArea(int[] heights) {
   
        int result = 0;
        for (int i = 0; i < heights.length; i++) {
   
            int min = heights[i];
            for (int j = i; j < heights.length; j++) {
   
                min = Math.min(min, heights[j]);
                result = Math.max(result, (j - i + 1) * min);

            }
        }
        return result;
    }
}

思路二

中心扩展法。

思路三
使用单调栈,单调栈适用于什么场景?找最值,单调栈:栈顶是最大的元素,单调队列:队头是最大的元素
说白了,这题考的基础模型其实就是:在一维数组中对每一个数找到第一个比自己小的元素。这类“在一维数组中找第一个满足某种条件的数”的场景就是典型的单调栈应用场景。
具体思路
暴力方法是直接计算,会有很多重复计算,同时时间复杂度较高。所以我们可以用空间换取时间的做法,降低时间复杂度。
对于每一个height[i],我们可以向左和向右对外扩展,直到找到比它小的数才中断扩展。这个时候就是包含height【i】的最大矩形面积。
新增定义两个数组left,right,left[i]分别表示:

  1. 对于元素num[i],left[i]表示在num[i]左边的比num[i]小的最近的元素
  2. 对于元素num[i],right[i]表示在nums[i]右边的比num[i]小的最近的元素
    那么计算公式就是:
    height[i] * (right[i] -left[i])

考虑边界情况:
如果左边的数都比height[i]大,left[i]=-1,
如果右边的数都比height[i]大,right=height.length

那么如何求left[i]和right[i]呢
如果直接向左或向右遍历,那么复杂度依然为On^2,对于这种每个元素按照某个顺序遍历都必须插入到栈,而且插入元素后栈顶一直保持是最大的数的场景,我们可以使用单调栈。单调栈:从栈底到栈顶,是单调递增的。而且,元素插入的顺序都是有意义的。

时间复杂度分析

单调栈的时间复杂度是多少?直接计算十分困难,但是我们可以发现:

每一个位置只会入栈一次(在枚举到它时),并且最多出栈一次。

因此当我们从左向右/总右向左遍历数组时,对栈的操作的次数就为 O(N)O(N)。所以单调栈的总时间复杂度为 O(N)
代码

class Solution {
   
    public int largestRectangleArea(int[] heights) {
   
        int n = heights.length;
        int[] left = new int[n];
        int[] right = new int[n];
        
        Deque<Integer> mono_stack = new ArrayDeque<Integer>();
        for (int i = 0; i < n; ++i) {
   
            while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
   
                mono_stack.pop();
            }
            left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值