首页 > 编程语言 >「代码随想录算法训练营」第四十二天 | 单调栈 part2

「代码随想录算法训练营」第四十二天 | 单调栈 part2

时间:2024-08-20 11:48:07浏览次数:15  
标签:柱子 int 随想录 height part2 st ans heights 第四十二

42. 接雨水

题目链接:https://leetcode.cn/problems/trapping-rain-water/
文章讲解:https://programmercarl.com/0042.接雨水.html
题目难度:困难
视频讲解:https://www.bilibili.com/video/BV1uD4y1u75P/
题目状态:这道题目在LeetCode Top100中做过,使用两种方法,再回顾一下

思路一:单调栈

  1. 栈的作用

    • 栈用于存储柱子的索引,确保栈中的高度是递减的。
  2. 遍历数组

    • 对于每个柱子,如果当前柱子高度大于栈顶柱子高度,说明可以形成一个凹槽来积水。
  3. 计算积水

    • 弹出栈顶元素,作为凹槽的底部。
    • 如果栈为空,说明没有左边界,无法积水。
    • 否则,计算左边界(新的栈顶)与当前柱子之间的宽度。
    • 计算高度差:min(height[left], height[i]) - height[top]
    • 计算当前积水量并累加到结果中。
  4. 继续遍历

    • 将当前柱子的索引压入栈中,继续处理下一个柱子。

代码一:

class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0;
        stack<int> stk;
        int n = height.size();
        for(int i = 0; i < n; ++i) {
            while(!stk.empty() && height[i] > height[stk.top()]) {
                int top = stk.top();
                stk.pop();
                if(stk.empty()) break;
                int left = stk.top();
                int currWidth = i - left - 1;
                int currHeight = min(height[left], height[i]) - height[top];
                ans += currWidth * currHeight;
            }
            stk.push(i);
        }
        return ans;
    }
};

消耗一:

image

思路二:动态规划

  1. 初始化

    • 检查输入数组是否为空。如果是,直接返回0。
  2. 计算左边最大高度

    • 创建一个数组 leftMax,其中 leftMax[i] 存储从位置0到位置i的最大高度。
    • 通过遍历数组,逐步更新 leftMax
  3. 计算右边最大高度

    • 创建一个数组 rightMax,其中 rightMax[i] 存储从位置i到数组末尾的最大高度。
    • 通过反向遍历数组,逐步更新 rightMax
  4. 计算总积水量

    • 遍历每个位置,计算当前位置能存储的水量:min(leftMax[i], rightMax[i]) - height[i]
    • 将每个位置的水量累加到总水量中。
  5. 返回结果

    • 返回总积水量。

代码二:

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n == 0) return 0;
        
        vector<int> leftMax(n);
        leftMax[0] = height[0];
        for(int i = 1; i < n; ++i) {
            leftMax[i] = max(leftMax[i - 1], height[i]);
        }

        vector<int> rightMax(n);
        rightMax[n - 1] = height[n - 1];
        for(int i = n - 2; i >= 0; --i) {
            rightMax[i] = max(rightMax[i + 1], height[i]);
        }

        int ans = 0;
        for(int i = 0; i < n; ++i) {
            ans += min(leftMax[i], rightMax[i]) - height[i];
        }
        return ans;
    }
};

消耗二:

image

84. 柱状图中最大的矩形

题目链接:https://leetcode.cn/problems/largest-rectangle-in-histogram/
文章讲解:https://programmercarl.com/0084.柱状图中最大的矩形.html
题目难度:困难
视频讲解:https://www.bilibili.com/video/BV1Ns4y1o7uB/
题目状态:不会做,看题解

思路一:双指针

  1. 初始化:

    • minLeftIndex[0] 初始化为 -1,表示最左边界。
    • minRightIndex[size - 1] 初始化为 size,表示最右边界。
  2. 计算 minLeftIndex:

    • 从左到右遍历柱子,对于每个柱子 i,向左寻找第一个高度小于 heights[i] 的柱子。
    • 使用变量 ti-1 开始向左查找,更新 minLeftIndex[i] 为找到的下标。
    • 如果当前柱子 t 的高度大于等于 heights[i],继续向左查找 minLeftIndex[t]
  3. 计算 minRightIndex:

    • 从右到左遍历柱子,对于每个柱子 i,向右寻找第一个高度小于 heights[i] 的柱子。
    • 使用变量 ti+1 开始向右查找,更新 minRightIndex[i] 为找到的下标。
    • 如果当前柱子 t 的高度大于等于 heights[i],继续向右查找 minRightIndex[t]
  4. 计算最大矩形面积:

    • 遍历每个柱子 i,计算以该柱子为高的最大矩形面积:heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1)
    • 更新 result 为所有计算出的矩形面积的最大值。
  5. 返回结果:

    • 返回 result,即最大矩形的面积。

代码一:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int len = heights.size();
        vector<int> minLeftIndex(len);
        vector<int> minRightIndex(len);
        minLeftIndex[0] = -1;
        for(int i = 1; i < len; ++i) {
            int t = i - 1;
            while(t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
            minLeftIndex[i] = t;
        }
        minRightIndex[len - 1] = len;
        for(int i = len - 2; i >= 0; --i) {
            int t = i + 1;
            while(t < len && heights[t] >= heights[i]) t = minRightIndex[t];
            minRightIndex[i] = t;
        }
        int ans = 0;
        for(int i = 0; i < len; ++i) {
            int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);
            ans = max(sum, ans);
        }
        return ans;
    }
};

消耗一:

image

思路二:单调栈

  1. 初始化栈:

    • 插入 0 后,栈中初始含有下标 0
  2. 遍历柱子:

    • 从下标 1 开始遍历 heights 数组。
  3. 处理情况:

    • heights[i] < heights[st.top()] 时,表示可以计算以栈顶柱子为高的矩形面积。
    • 不断弹出栈顶元素,直到栈为空或栈顶柱子高度不大于当前柱子高度。
    • 计算面积:
      • mid 是当前弹出的柱子下标。
      • w = i - st.top() - 1 是矩形的宽度。
      • h = heights[mid] 是矩形的高度。
      • 更新 result 为最大值。
  4. 返回结果:

    • 返回 result,即最大矩形的面积。

代码二:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int ans = 0;
        stack<int> st;
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        st.push(0);
        for(int i = 1; i < heights.size(); ++i) {
            if(heights[i] >= heights[st.top()]) st.push(i);
            else {
                while(!st.empty() && heights[i] < heights[st.top()]) {
                    int mid = st.top();
                    st.pop();
                    if(!st.empty()) {
                        int left = st.top();
                        int right = i;
                        int w = right - left - 1;
                        int h = heights[mid];
                        ans = max(ans, w * h);
                    }
                }
                st.push(i);
            }
        }
        return ans;
    }
};

消耗二:

image

标签:柱子,int,随想录,height,part2,st,ans,heights,第四十二
From: https://www.cnblogs.com/frontpen/p/18367606

相关文章

  • 代码随想录day35 || 416 分割等和子集
    背包问题有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。//pake//// @Description:// @paramweights:物品i对应重量// @paramvalue:物品i对应价值// @......
  • 重生 之 被裁员后开滴滴之前学习了鸿蒙(part2)
    12.ArkUI-界面1.组件1.定义容器组件(){//内容}基础组件(参数)ps:UI界面构建的最小元素是组件ps:最外层只能有一个容器组件(距离build最近的)2.组件属性方法组件(){}.属性方法1(参数).属性方法2(参数).属性方法3(参数)……ps:若是基本组件可......
  • 「代码随想录算法训练营」第四十一天 | 单调栈 part1
    739.每日温度题目链接:https://leetcode.cn/problems/daily-temperatures/文章讲解:https://programmercarl.com/0739.每日温度.html题目难度:中等视频讲解:https://www.bilibili.com/video/BV1my4y1Z7jj/题目状态:看题解思路:定义一个单调栈,该栈存放下标,规则是要保持其下标对......
  • Day34 动态规划Part2
    目录任务62.不同路径思路63.不同路径II思路343.整数拆分思路96.不同的二叉搜索树思路任务62.不同路径一个机器人位于一个mxn网格的左上角(起始点在下图中标记为“Start”)。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finis......
  • 代码随想录day34 || 62 不同路径,63 不同路径||,343整数拆分,96 不同搜索二叉树
    不同路径funcuniquePaths(mint,nint)int{ //dp五部曲 //dp数组以及下标的含义dp[i][j]代表从0,0走到i,j的不同路径条数 //递推公式 dp[i][j]=dp[i-1][j]+dp[i][j-1] //dp数组的初始化dp[i][0]==dp[0][j]=1 //遍历顺序 外层按照行,内层按照列遍历......
  • 代码随想录Day18
    530.二叉搜索树的最小绝对差给你一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值。差值是一个正数,其数值等于两值之差的绝对值。示例1:输入:root=[4,2,6,1,3]输出:1示例2:输入:root=[1,0,48,null,null,12,49]输出:1提示:树中节点的数目范围是......
  • 代码随想录算法训练营第11天|二叉树part01
    理论基础需要了解二叉树的种类,存储方式,遍历方式以及二叉树的定义二叉树纯理论方面还是比较简单,以前都学过,没什么可讲的。满二叉树就是满了,完全二叉树就是层满了(而且是左边)。平衡二叉搜索树就是左右深度绝对值差1。一般采用链式存储方式,顺序存储结构如果父节点的数组......
  • 代码随想录算法训练营第10天|栈与队列part02
    150.逆波兰表达式求值本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题classSolution{public:intevalRPN(vector<string>&tokens){stack<longlong>st;for(conststring&token:tokens){if(token=="+......
  • 代码随想录Day17
    654.最大二叉树给定一个不重复的整数数组nums。最大二叉树可以用下面的算法从nums递归地构建:创建一个根节点,其值为nums中的最大值。递归地在最大值左边的子数组前缀上构建左子树。递归地在最大值右边的子数组后缀上构建右子树。返回nums构建的最大二叉树......
  • 【代码随想录训练营第42期 Day32打卡 - 从零开始动态规划 - LeetCode 509. 斐波那契数
    目录一、做题心得二、动规五步走三、题目与题解题目一:509.斐波那契数题目链接题解1:记忆性递归 题解2:动态规划题目二:70.爬楼梯 题目链接题解:动态规划题目三:746.使用最小花费爬楼梯题目链接题解:动态规划三、小结一、做题心得今天开始动态规划章节的第一......