「代码随想录算法训练营」第四十二天 | 单调栈 part2
1.「代码随想录算法训练营」第二天 | 数组 part22.「代码随想录算法训练营」第三天 | 链表 part13.「代码随想录算法训练营」第四天 | 链表 part24.「代码随想录算法训练营」第一天(补) | 数组 part15.「代码随想录算法训练营」第五天 | 哈希表 part16.「代码随想录算法训练营」第六天 | 哈希表 part27.「代码随想录算法训练营」第七天 | 字符串 part18.「代码随想录算法训练营」第八天 | 字符串 part29.「代码随想录算法训练营」第九天 | 栈与队列 part110.「代码随想录算法训练营」第十天 | 栈与队列 part211.「代码随想录算法训练营」第十一天 | 二叉树 part112.「代码随想录算法训练营」第十二天 | 二叉树 part213.「代码随想录算法训练营」第十三天 | 二叉树 part314.「代码随想录算法训练营」第十四天 | 二叉树 part415.「代码随想录算法训练营」第十五天 | 二叉树 part516.「代码随想录算法训练营」第十六天 | 二叉树 part617.「代码随想录算法训练营」第十七天 | 二叉树 part718.「代码随想录算法训练营」第十八天 | 二叉树 part819.「代码随想录算法训练营」第十九天 | 回溯算法 part120.「代码随想录算法训练营」第二十天 | 回溯算法 part221.「代码随想录算法训练营」第二十一天 | 回溯算法 part322.「代码随想录算法训练营」第二十二天 | 回溯算法 part423.「代码随想录算法训练营」第二十三天 | 贪心算法 part124.「代码随想录算法训练营」第二十四天 | 贪心算法 part225.「代码随想录算法训练营」第二十五天 | 贪心算法 part326.「代码随想录算法训练营」第二十六天 | 贪心算法 part427.「代码随想录算法训练营」第二十七天 | 贪心算法 part528.「代码随想录算法训练营」第二十八天 | 动态规划 part129.「代码随想录算法训练营」第二十九天 | 动态规划 part230.「代码随想录算法训练营」第三十天 | 动态规划 part331.「代码随想录算法训练营」第三十一天 | 动态规划 part432.「代码随想录算法训练营」第三十二天 | 动态规划 part533.「代码随想录算法训练营」第三十三天 | 动态规划 part634.「代码随想录算法训练营」第三十四天 | 动态规划 part735.「代码随想录算法训练营」第三十五天 | 动态规划 part836.「代码随想录算法训练营」第三十六天 | 动态规划 part937.「代码随想录算法训练营」第三十七天 | 动态规划 part1038.「代码随想录算法训练营」第三十八天 | 动态规划 part1139.「代码随想录算法训练营」第三十九天 | 动态规划 part1240.「代码随想录算法训练营」第四十一天 | 单调栈 part141.「代码随想录算法训练营」第四十天 | 动态规划 part13
42.「代码随想录算法训练营」第四十二天 | 单调栈 part2
43.「代码随想录算法训练营」第四十三天 | 图论 part144.「代码随想录算法训练营」第四十四天 | 图论 part245.「代码随想录算法训练营」第四十五天 | 图论 part346.「代码随想录算法训练营」第四十六天 | 图论 part447.「代码随想录算法训练营」第四十七天 | 图论 part548.「代码随想录算法训练营」第四十八天 | 图论 part649.「代码随想录算法训练营」第四十九天 | 图论 part750.「代码随想录算法训练营」第五十天 | 图论 part851.「代码随想录算法训练营」第五十一天 | 图论 part952.「代码随想录算法训练营」第五十二天 | 图论 part1053.「代码随想录算法训练营」完结!42. 接雨水
题目链接:https://leetcode.cn/problems/trapping-rain-water/
文章讲解:https://programmercarl.com/0042.接雨水.html
题目难度:困难
视频讲解:https://www.bilibili.com/video/BV1uD4y1u75P/
题目状态:这道题目在LeetCode Top100中做过,使用两种方法,再回顾一下
思路一:单调栈
-
栈的作用:
- 栈用于存储柱子的索引,确保栈中的高度是递减的。
-
遍历数组:
- 对于每个柱子,如果当前柱子高度大于栈顶柱子高度,说明可以形成一个凹槽来积水。
-
计算积水:
- 弹出栈顶元素,作为凹槽的底部。
- 如果栈为空,说明没有左边界,无法积水。
- 否则,计算左边界(新的栈顶)与当前柱子之间的宽度。
- 计算高度差:
min(height[left], height[i]) - height[top]
。 - 计算当前积水量并累加到结果中。
-
继续遍历:
- 将当前柱子的索引压入栈中,继续处理下一个柱子。
代码一:
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; } };
消耗一:
思路二:动态规划
-
初始化:
- 检查输入数组是否为空。如果是,直接返回0。
-
计算左边最大高度:
- 创建一个数组
leftMax
,其中leftMax[i]
存储从位置0到位置i的最大高度。 - 通过遍历数组,逐步更新
leftMax
。
- 创建一个数组
-
计算右边最大高度:
- 创建一个数组
rightMax
,其中rightMax[i]
存储从位置i到数组末尾的最大高度。 - 通过反向遍历数组,逐步更新
rightMax
。
- 创建一个数组
-
计算总积水量:
- 遍历每个位置,计算当前位置能存储的水量:
min(leftMax[i], rightMax[i]) - height[i]
。 - 将每个位置的水量累加到总水量中。
- 遍历每个位置,计算当前位置能存储的水量:
-
返回结果:
- 返回总积水量。
代码二:
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; } };
消耗二:
84. 柱状图中最大的矩形
题目链接:https://leetcode.cn/problems/largest-rectangle-in-histogram/
文章讲解:https://programmercarl.com/0084.柱状图中最大的矩形.html
题目难度:困难
视频讲解:https://www.bilibili.com/video/BV1Ns4y1o7uB/
题目状态:不会做,看题解
思路一:双指针
-
初始化:
minLeftIndex[0]
初始化为-1
,表示最左边界。minRightIndex[size - 1]
初始化为size
,表示最右边界。
-
计算
minLeftIndex
:- 从左到右遍历柱子,对于每个柱子
i
,向左寻找第一个高度小于heights[i]
的柱子。 - 使用变量
t
从i-1
开始向左查找,更新minLeftIndex[i]
为找到的下标。 - 如果当前柱子
t
的高度大于等于heights[i]
,继续向左查找minLeftIndex[t]
。
- 从左到右遍历柱子,对于每个柱子
-
计算
minRightIndex
:- 从右到左遍历柱子,对于每个柱子
i
,向右寻找第一个高度小于heights[i]
的柱子。 - 使用变量
t
从i+1
开始向右查找,更新minRightIndex[i]
为找到的下标。 - 如果当前柱子
t
的高度大于等于heights[i]
,继续向右查找minRightIndex[t]
。
- 从右到左遍历柱子,对于每个柱子
-
计算最大矩形面积:
- 遍历每个柱子
i
,计算以该柱子为高的最大矩形面积:heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1)
。 - 更新
result
为所有计算出的矩形面积的最大值。
- 遍历每个柱子
-
返回结果:
- 返回
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; } };
消耗一:
思路二:单调栈
-
初始化栈:
- 插入
0
后,栈中初始含有下标0
。
- 插入
-
遍历柱子:
- 从下标
1
开始遍历heights
数组。
- 从下标
-
处理情况:
- 当
heights[i] < heights[st.top()]
时,表示可以计算以栈顶柱子为高的矩形面积。 - 不断弹出栈顶元素,直到栈为空或栈顶柱子高度不大于当前柱子高度。
- 计算面积:
mid
是当前弹出的柱子下标。w = i - st.top() - 1
是矩形的宽度。h = heights[mid]
是矩形的高度。- 更新
result
为最大值。
- 当
-
返回结果:
- 返回
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; } };
消耗二:
合集:
「代码随想录算法训练营」
分类:
算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?