Leetcode-739.每日温度(双思路分析)

题目链接
在这里插入图片描述

方法一:单调栈

作为一道要依序比较元素之间大小、求差,最先想到的就是利用
栈真的是一个很好用的数据结构,利用其后进先出的模式,用起来相当爽。以前做过匹配括号,可以说和这道题类似,只要符合条件,就入栈、弹栈。

这到题,找比这个数大的一个数,两下标一减,就能得到要等几天才会有较高温度,就意味着,每个元素都要入栈,只有符合条件的后(比这个栈顶元素大),就能进行弹栈,并进行下一次的入栈判断。

而题目要求要返回一个数组,则要创建一个数组来为每一天储存信息。

拓展思维:我们都会习惯性的认为,使用栈来储存当天气温的温度,其实,我们还可以储存温度在原数组中的下标,这样有一个好处,就是,我们可以直接使用创建的数组来保存相应的位置的相隔天数,这样可以避免重复计算。

还有关键的一点:要将气温与栈顶所储存的下标所代表的气温进行比较弹栈,但是首先,栈中要不为空。所以每次弹栈的前提都是要栈不为空。

看代码

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int len=temperatures.size();
        stack<int> st;
        int j=0;
        vector<int> v(len);
        for(int i=0;i<len;i++)
        {
            while(!st.empty()&&temperatures[i]>temperatures[st.top()])
            {
                v[st.top()]=i-st.top();
                st.pop();
            }
            st.push(i);
        }
        return v;
    }
};

这比较简洁吧。

分析思想

while循环是代表此时,与栈顶元素比较,已经符合条件,且可以进行下标相减存数组,且弹栈了。但是有一个测试用例,就是
如果是75,72,69,71,76,78,这样的测试用例,怎么办?
这个while就很好的处理了这个问题,前面提到了,利用栈顶不用进行重复计算,这个方案就是为了处理这样的温度减小的测试用例。

使用了栈,就肯定要使用栈顶这个独特的特性,不然直接使用数组就不是了

在这里插入图片描述
只有元素比“栈顶元素”大,才能弹栈,否则,就只能入栈,对,就是入栈。
在这里插入图片描述
栈不为空,拿i元素与栈顶元素比较,符合条件,进入循环。

提问:为什么用while循环不用if判断

其实,这个问题,就是回答了,这个算法是如何避免了重复将某些元素入栈。
你想想,如果比较一次后,弹栈了,栈就空了,就意味着已经找到了,比栈顶元素大的元素,符合条件。

如果像上面的举例一样,谈论一次栈后,还有元素呢?
其实,你要意识到,只要能入栈,可不仅仅是栈是空的,还有一点,就是这个元素并不比栈顶元素大,这是关键的一点,而且,这个元素后面还有元素也入了栈,这就代表,这个元素也不比上一个元素大,这样不断,比较、弹栈,正好可以找到,比栈中元素大的第一个元素,同时,再利用栈中储存的是元素的下标,
这样直接给vector数组中赋值,这样,既不会在一个位置重复赋值,还能把前面没找到大的元素一锅端了,可以避免重复运算,直接一步到位,

所以时间复杂度是O(N)

方法二:KMP的思想

众所周知,KMP是一个非常高效的模式串匹配算法,对KMP不太了解的同志可以看看这篇
认知BF与KMP算法
KMP,就是利用一个数组来保存已经遍历过的字符串的信息,再利用已经遍历过的信息去减少重复运算。
这个方法用的就是这个思想。

分析思想

KMP要利用过去的信息去回溯,这个当然也一样,但是,我们不可能从下标0开始遍历,因为,即使是KMP其next数组的第一个元素也是确定的-1,所以,我们要从数组的最后一个元素开始,因为,最后一个元素是不可能有元素比它还大的,它自己就是最后一个,所以其所标志的元素就是 0 。有了第一个打头就行。

在这里插入图片描述

同样,要利用元素的下标相减,来得到准确值。但是有些情况,
比如,上面的例子,元素呈递减的情况。
我们利用KMP的思想:主串下标不会退,一直往前走,子串下标回退到next数组指定的位置。
要保证遍历温度数组的下标不能回退,始终像前走。而,回退的信息都储存在vector数组(也就是题目要返回的答案)。因为数组储存的都是后面间隔几个元素比当前元素大。
这样的信息保存在另一个下标来处理回退信息。
如果回退到对应vector元素是0,就代表这已经没法回退了,也就是说,如果这个元素都不比 i 所表示的元素大,而vector数组中对应的是0,就代表后面也不会有比这个还大的了,就意味着,根本在后面就找不到比当前元素还大的,其对应下标就是0.

图解算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

看代码

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int len=temperatures.size();
        vector<int> v(len);
        v[len-1]=0;
        int j=len-1;
        int i=len-2;
        while(i>=0)
        {
            if(j==i||temperatures[i]<temperatures[j])
            {
                v[i]=j-i;
                i--;
                j=i+1;    
            }
            else
            {
                j+=v[j];
                temperatures[j]>temperatures[i]?j=j:(v[j]==0?j=i:j=j);
            }
        }
        return v;
    }
};

这里,为了处理,i元素后没有比他大的元素,这里要让i==j也能进入处理,并且更新 i 与 j 。

感谢大佬观看,如有问题,烦请指点一二,感谢。
在这里插入图片描述

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值