739.每日温度
力扣题目链接/文章讲解
视频讲解
暴力解法很容易想到。外层 for 遍历填充 answer,内层 for 针对每一天去寻找下一个更高温度
直接超时
本题可以采用单调栈解决!
什么是单调栈?
从名字上就听的出来,单调栈中存放的数据应该是有序的
维护单调栈的关键就是维护这个有序性,假设我们需要维护一个从栈顶到栈底单调递增的栈
在入栈元素时,如果栈为空或入栈元素值小于栈顶元素值,则入栈
否则,如果直接入栈则会破坏栈的单调性,则需要先把比入栈元素小的栈顶元素全部出栈后,再入栈
本题怎么利用单调栈解决?本质上是利用一个栈来记录我们遍历过的元素
本题大致过程是单调栈中存放元素下标,按照元素值从栈顶到栈底递增存放,元素出栈时记录一次结果
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
// 递增栈,注意栈中存的是temperatures的下标,但“递增”形容的是temperatures的值
// 递增栈指从栈顶到栈底元素递增
vector<int> answer(temperatures.size(), 0); // 存放结果,题目要求默认为0
st.push(0);
for (int i = 1; i < temperatures.size(); ++i) {
if (temperatures[i] <= temperatures[st.top()])
st.push(i); // 递增栈,当入栈元素小于等于栈顶元素,则入栈不会破坏单调性
else { // 否则需要不断将比入栈元素小的元素全部出栈
while (!st.empty() && temperatures[i] > temperatures[st.top()]) // 注意栈非空
{
answer[st.top()] = i - st.top(); // 出栈时记录一次结果
st.pop();
}
st.push(i); // 然后再入栈
}
}
return answer;
}
};
详细过程可以见视频讲解,感觉已经很清晰了
496.下一个更大元素 I
力扣题目链接/文章讲解
视频讲解
一维数组中,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素,此时我们又可以想到用单调栈
需要用一个栈来记录遍历过的元素,本题我们要在 nums2 中找下一个更大元素,因此遍历 nums2,并用单调递增栈记录
在入栈元素时,如果栈为空或入栈元素值小于栈顶元素值,则入栈
否则,如果直接入栈则会破坏栈的单调性,则需要先把比入栈元素小的栈顶元素全部出栈后,再入栈
本题大致过程是单调栈中存放元素,按照元素值从栈顶到栈底递增存放,元素出栈时记录结果
stack<int> st; // 从栈顶到栈底元素单调递增的栈
st.push(nums2[0]);
for (int i = 1; i < nums2.size(); ++i) { // 遍历nums2
if (nums2[i] <= st.top()) // 入栈元素小于等于栈顶元素,直接入栈不会破坏单调性
st.push(nums2[i]);
else {
while (!st.empty() && nums2[i] > st.top()) { // 将比入栈元素小的元素全部出栈后
// 元素出栈时做记录
st.pop();
}
st.push(nums2[i]); // 再入栈
}
}
此时我们看看怎么记录结果
根据题目要求,当出栈元素是 nums1 中的元素时,才记录在 nums1 中元素对应下标的位置
为了实现这种需求,我们先搭建一个 nums1 中元素到元素下标的映射
unordered_map<int, int> umap; // k:nums1中元素 v:元素对应下标
for (int i = 0; i < nums1.size(); ++i)
umap[nums1[i]] = i;
然后在记录结果的时候看看出栈元素是否为 nums1 中的元素即可
if (umap.count(st.top()) > 0) // 刚才映射中有记录,说明出栈元素是nums1中的元素
{
ans[umap[st.top()]] = nums2[i];
// umap[st.top()]获取出栈元素在nums1中的下标位置,需要将结果记录在ans的该位置
// nums2[i]就是出栈元素右侧的第一个比其大的元素
}
整体代码如下
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> ans(nums1.size(), -1);
unordered_map<int, int> umap; // k:nums1中元素 v:元素对应下标
for (int i = 0; i < nums1.size(); ++i)
umap[nums1[i]] = i;
stack<int> st; // 从栈顶到栈底元素单调递增的栈
st.push(nums2[0]);
for (int i = 1; i < nums2.size(); ++i) { // 遍历nums2
if (nums2[i] <= st.top()) // 入栈元素小于等于栈顶元素,直接入栈不会破坏单调性
st.push(nums2[i]);
else {
while (!st.empty() && nums2[i] > st.top()) { // 先不断将比入栈元素小的元素全部出栈后
// 元素出栈时做记录
if (umap.count(st.top()) > 0) // 刚才映射中有记录,说明出栈元素是nums1中的元素
{
ans[umap[st.top()]] = nums2[i];
// umap[st.top()]获取出栈元素在nums1中下标位置,需要将结果记录在ans的该位置
// nums2[i]就是出栈元素右侧的第一个比其大的元素
}
st.pop();
}
st.push(nums2[i]); // 再入栈
}
}
return ans;
}
};
回顾总结
单调栈的关键就是维护栈中元素的单调性
关键就是入栈时候不能破坏栈中元素的单调性
单调栈适合解决的问题:一维数组中,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素
单调栈解决问题的过程需要多看视频和动图解析,还是很容易理解的
另外简单说一下确定递增递减栈的思路过程:(从栈顶到栈底递增还是递减)
找下一个更大,说明需要记录下一个更大,即遇到更大的入栈才需要出栈并记录,说明遇到更大的入栈会破坏单调性,因此是递增栈
找下一个更小,说明需要记录下一个更小,即遇到更小的入栈才需要出栈并记录,说明遇到更小的入栈会破坏单调性,因此是递减栈