前言
面试中,栈这个数据结构啊,考察还是比较多的,思来想去,我又想起来力扣当中一道栈结构相关的算法题,我现在就把这道题介绍给大家
题目
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
思路No.1
看完题目,我灵光乍现,这玩意不就是找当前元素右边第一个大于它的元素吗?没有大于它的,那最后结果不是0吗?于是我飞快的使用暴力双循环!毕竟又熟悉,又稳,妥的一批!
代码
var dailyTemperatures = function(temperatures) {
let res = []
//每个值赋0
for(let i = 0; i < temperatures.length;i++) {
res[i] = 0
}
for(let i = 0; i < temperatures.length - 1; i++) {
for(let j = i + 1; j < temperatures.length; j++) {
if(temperatures[j] > temperatures[i]) {
res[i] = j - i > 0? j - i: 0;
break; //找到了就停下,继续下一轮
}
}
}
return res
};
简简单单这不是嘛,放到力扣一看!
哟呵,这不是也很nice,内存消耗不大,只用了一个数组,但是时间复杂度上太高了,是O(n^2)。
之后面试官又问:还有别的方法吗?这个时间我看的很不爽
我:嗯....,这个......,那个.......
思路No.2
再次思考良久(偷瞄一眼大佬评论区),又出现了单调栈的解法,哈哈哈!
我们就分析例一 [73,74,75,71,69,72,76,73]
- 我们先将数组第一个元素压入栈,之后循环数组,让后面的元素与该元素作比较
- 一种为大于栈顶元素,此时计算res[i]为当前元素与栈顶元素的差值,并将栈顶元素出栈,当前元素进栈,作后续比较
- 一种为小于栈顶元素,我们继续将该元素压入栈顶
- 循环结束,返回结果
将result数组全部赋值为0。
我们模拟一下过程
- 73 入栈, 74>73,计算res[0] 为 元素下标差1
- 之后73出栈,74入栈, 75与74比较,计算res[1] = 1
- 74出栈,75入栈,之后与71比较,将71入栈,此时栈里面有[75, 71]
- 之后69又入栈,与72比较,计算res[4] = 1, 此时栈内还有元素,仍然需要比较,72>71,计算res[3] = 2
- 碰到大哥大75,将71出栈,72入栈,此时与76比较,计算res[5]=1,栈内仍然有元素,将其与76比较,计算res[2] = 4
- 此时剩余73与76比较,入栈,但是不慌,我们提前初始化,右边没有最大的就为0
- 返回结果即可
代码中由于需要计算下标,我们将用下标替代元素入栈,思路还是一样的。
代码
var dailyTemperatures = function(T) {
let result = Array(T.length).fill(0);
let st = []
st.push(0);
for (let i = 1; i < T.length; i++) {
if (T[i] <= T[st[st.length - 1]]) { // 小于或者等于
st.push(i); //下标入栈
} else {
while (st.length && T[i] > T[st[st.length - 1]]) { // 大于
result[st[st.length - 1]] = i - st[st.length - 1];
st.pop();
}
st.push(i);
}
}
return result;
};
看一下力扣,很nice啊!但是内存消耗过多了,无伤大雅!至少在时间复杂度方面就好多了!
思路No.2进阶
写完代码之后,又思考良久(再次偷瞄评论区),发现居然又有改进的地方,我真的有点服了,这些大佬太卷了!
他是将情况分为一种,就是大于的一种。其实该出栈的还是出栈,入栈的还是入栈。
代码
var dailyTemperatures = function(T) {
let result = Array(T.length).fill(0);
let st = []
st.push(0);
for (let i = 1; i < T.length; i++) {
while (st.length && T[i] > T[st[st.length - 1]]) { // 注意栈不能为空
result[st[st.length - 1]] = i - st[st.length - 1];
st.pop();
}
st.push(i);
}
return result;
};
果然大佬就是大佬,真滴强!
总结
写完算法之后,有些地方真是受益匪浅,建议各位刷算法的时候,如果没有什么太好的思路,或者说有思路但不是很清晰,看看评论区大佬们的算法! 避免走弯路,当然我的意思不是说走弯路不好,我也是在刷算法时走多了弯路,弯路肯定要走的,但是有的时候自己确实愚钝,时间花费过多了,如何在最短的时间内,自己存在思考,又能学习算法,才是重要的,当然,大佬除外!而下一次遇见类似的,想起用法,说明你差不多掌握了!
加油,我是小白,我们一起学习!