面试官:再来一道栈结构!

69 阅读4分钟

前言

面试中,栈这个数据结构啊,考察还是比较多的,思来想去,我又想起来力扣当中一道栈结构相关的算法题,我现在就把这道题介绍给大家

题目

请根据每日 气温 列表 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吗?于是我飞快的使用暴力双循环!毕竟又熟悉,又稳,妥的一批!

src=http __img.soogif.com_7MlMhGACtSeIJ6uWT2GcpDnMoyY6xODo.gif&refer=http __img.soogif.gif

代码

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
};

简简单单这不是嘛,放到力扣一看!

图片.png

哟呵,这不是也很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啊!但是内存消耗过多了,无伤大雅!至少在时间复杂度方面就好多了! 图片.png

思路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;
};

果然大佬就是大佬,真滴强!

图片.png

总结

写完算法之后,有些地方真是受益匪浅,建议各位刷算法的时候,如果没有什么太好的思路,或者说有思路但不是很清晰,看看评论区大佬们的算法! 避免走弯路,当然我的意思不是说走弯路不好,我也是在刷算法时走多了弯路,弯路肯定要走的,但是有的时候自己确实愚钝,时间花费过多了,如何在最短的时间内,自己存在思考,又能学习算法,才是重要的,当然,大佬除外!而下一次遇见类似的,想起用法,说明你差不多掌握了!

加油,我是小白,我们一起学习!