「代码随想录算法训练营」第四十一天 | 单调栈 part1
739. 每日温度
题目链接:https://leetcode.cn/problems/daily-temperatures/
文章讲解:https://programmercarl.com/0739.每日温度.html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV1my4y1Z7jj/
题目状态:看题解
思路:
定义一个单调栈,该栈存放下标,规则是要保持其下标对应的温度值从栈底到栈头是单调递减的。再定义一个和题目数组大小相等的数组ans
存放结果,初始化为0。具体步骤如下:
- 先将第一个元素的下标存入栈中。
- 循环遍历温度数组:
- 若当前温度小于等于栈头元素的温度,将当前温度的下标压入栈。
- 若当前温度大于栈头元素的温度,将栈中比当前温度低的元素都弹出,在弹出的时候将其压入结果数组中(i-st.top()),直到栈头大于当前温度,将当前温度的下标压入栈。
- 遍历结束后,返回结果数组。
代码:
class Solution { public: vector<int> dailyTemperatures(vector<int>& temperatures) { int len = temperatures.size(); stack<int> st; vector<int> ans(len, 0); st.push(0); for(int i = 1; i < len; ++i) { if(temperatures[i] <= temperatures[st.top()]) st.push(i); else { while(!st.empty() && temperatures[i] > temperatures[st.top()]) { ans[st.top()] = i - st.top(); st.pop(); } st.push(i); } } return ans; } };
496. 下一个更大元素 I
题目链接:https://leetcode.cn/problems/next-greater-element-i/
文章讲解:https://programmercarl.com/0496.下一个更大元素I.html
题目难度:简单
视频讲解:https://www.bilibili.com/video/BV1jA411m7dX/
题目状态:用其他方法过的,看题解学习一下单调栈的方法
思路一:嵌套循环
非常传统的方法,遍历整个nums1
,每遍历一个元素就在nums2
中找到对应的元素下标,然后再在nums2
中从下标位置开始向后遍历,直到找到一个比元素大的元素,将其值填入结果数组中并跳出循环,若找不到直接返回,因为这个结果数组初始化的时候将其全部值初始化为-1
了。
代码一:
class Solution { public: vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { int len1 = nums1.size(), len2 = nums2.size(); vector<int> ans(len1, -1); for(int i = 0; i < len1; ++i) { auto it = find(nums2.begin(), nums2.end(), nums1[i]); int index = distance(nums2.begin(), it); for(int j = index; j < len2; ++j) { if(nums2[j] > nums1[i]) { ans[i] = nums2[j]; break; } } } return ans; } };
消耗:
思路二:单调栈
将nums1
压入一个unordered_map<int, int>
中,主要原因是它的查询和增删效率是最优的。
然后维护一个单调栈st
,这个栈从栈底到栈头是单调递减的,用来遍历nums2
,当遇到元素比栈头元素大的时候,就判断一下栈头元素是否在nums1
中存在,如果存在就表示其后面有比栈头元素高的元素,将这个元素值更新到结果数组中。
代码二:
class Solution { public: vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { int len1 = nums1.size(), len2 = nums2.size(); stack<int> st; vector<int> ans(len1, -1); if(len1 == 0) return ans; unordered_map<int, int> umap; for(int i = 0; i < len1; ++i) { umap[nums1[i]] = i; // key:下标元素,value:下标 } // 将nums2压入单调栈 st.push(0); for(int i = 1; i < len2; ++i) { if(nums2[i] <= nums2[st.top()]) st.push(i); else { while(!st.empty() && nums2[i] > nums2[st.top()]) { if(umap.count(nums2[st.top()]) > 0) { // 看看umap中是否存在该元素 int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()]在nums1中的下标 ans[index] = nums2[i]; } st.pop(); } st.push(i); } } return ans; } };
消耗:
503. 下一个更大元素 II
题目链接:https://leetcode.cn/problems/next-greater-element-ii/
文章讲解:https://programmercarl.com/0503.下一个更大元素II.html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV15y4y1o7Dw/
题目状态:自己的思路没通过,好奇怪,chatGPT帮忙修改了一下,直接把我思路改了
思路:
-
循环数组处理:
- 为了模拟循环数组,我们遍历数组两次。这样可以确保每个元素都能找到它的下一个更大元素,即使这个元素在数组的末尾。
-
使用栈:
- 栈用来存储索引,而不是元素值。这使我们能够直接在结果数组中更新对应位置的值。
-
遍历数组:
- 在每次遍历中,我们检查当前元素是否大于栈顶元素对应的值。
- 如果是,则更新结果数组中栈顶元素索引对应的值,并弹出栈顶。
- 如果当前索引在数组的前半部分(即小于
len
),我们将其索引压入栈中。
-
结果更新:
- 通过这种方式,所有元素的下一个更大元素都会在结果数组中被正确更新。
代码:
class Solution { public: vector<int> nextGreaterElements(vector<int>& nums) { int len = nums.size(); stack<int> st; vector<int> ans(len, -1); for(int i = 0; i < 2 * len; ++i) { int num = nums[i % len]; while(!st.empty() && nums[st.top()] < num) { ans[st.top()] = num; st.pop(); } if(i < len) st.push(i); } return ans; } };
消耗:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?