Description
Simulation
思路:我们先列一个表格分析一下示例数据是怎么来的
第1天 | 第2天 | 第3天 | 第4天 | 第5天 | 第6天 | 第7天 | 第8天 | |
---|---|---|---|---|---|---|---|---|
温度 | 73 | 74 | 75 | 71 | 69 | 72 | 76 | 73 |
下一个更高的温度 | 第2天 | 第3天 | 第7天 | 第6天 | 第6天 | 第7天 | 无 | 无 |
天数差 | 1 | 1 | 4 | 2 | 1 | 1 | 0 | 0 |
首先想到的当然是暴力解法,两层 for
循环挨个遍历一遍,计算天数差即可,时间复杂度O(n^2)。
get到暴力解法也很重要,毕竟不是什么时候都能想到最优解,而且我们还可以基于暴力解法进行下一步优化。
题目中要求计算下一个更高的温度的天数差,其实就是要找到自己右边第一个比自己大的元素, 然后计算下标之差。
很明显要用到一个单调减(栈头元素最小)的栈,通过O(n)的时间复杂度(即遍历一遍)就能找到每个元素的右边第一个比它大的元素,本质就是空间换时间。
-
为什么是单调减?
答:因为只有递减的时候,我们才能得到天数差,如74放入栈时,73即可出栈,第一天的天数差就得到了。
-
怎么计算天数差?
答:单调栈内只存放元素的下标即可,需要数值比较时直接使用
t[i]
即可。 -
模板怎么用?⏬
既然已经分析出要用单调栈,我们可以直接把三板斧(模板)使出来:
// 模板
stack<int> stk;
for (int i = 0; i < t.size(); i++) { // 遍历温度数组t
while (!stk.empty() && t[i] > t[stk.top()]) { // 出栈条件,保持单调减
stk.pop();
}
stk.push(i); // 入栈,放入下标
}
在脑中模拟一下出入栈的过程:
-
栈为空,73的下标0入栈,栈内元素
0
-
74 > 73,73出栈74入栈,天数差为1,栈内元素
1
-
75 > 74,74出栈75入栈,天数差为1,栈内元素
2
从第二步就可以看出来,我们需要在栈内元素出栈前通过下标计算天数差,增加一行即可:
while (!stk.empty() && t[i] > t[stk.top()]) { // 出栈条件,保持单调减
res[stk.top()] = i - stk.top(); // 添加计算
stk.pop();
}
Solution
完整代码如下,可以尝试一下,原题链接:
// hrh 8/28
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& t) {
vector<int> res(t.size());
stack<int> stk;
for (int i = 0; i < t.size(); i++) { // 遍历
while (!stk.empty() && t[i] > t[stk.top()]) { // 出栈条件
res[stk.top()] = i - stk.top(); // 计算天数差值
stk.pop(); // 保持单调减
}
stk.push(i); // 入栈
}
return res;
}
};
Conclusion
总结一下单调栈的分析思路:
-
一般来说,题目中要求找到一个元素左边(右边)第一个比自己大(小)的元素,我们应该首先想到单调栈。它的应用范围可以说是很窄,但缺点也是优点,题目类型很好辨认。
-
分析时应该首先分析单调性,判断单调减还是单调增,直接写出模板。
-
在模板的基础上进行删改,计算题目要求。