题目链接
方法一:单调栈
作为一道要依序比较元素之间大小、求差,最先想到的就是利用栈。 栈真的是一个很好用的数据结构,利用其后进先出的模式,用起来相当爽。以前做过匹配括号,可以说和这道题类似,只要符合条件,就入栈、弹栈。
这到题,找比这个数大的一个数,两下标一减,就能得到要等几天才会有较高温度,就意味着,每个元素都要入栈,只有符合条件的后(比这个栈顶元素大),就能进行弹栈,并进行下一次的入栈判断。
而题目要求要返回一个数组,则要创建一个数组来为每一天储存信息。
拓展思维:我们都会习惯性的认为,使用栈来储存当天气温的温度,其实,我们还可以储存温度在原数组中的下标,这样有一个好处,就是,我们可以直接使用创建的数组来保存相应的位置的相隔天数,这样可以避免重复计算。
还有关键的一点:要将气温与栈顶所储存的下标所代表的气温进行比较弹栈,但是首先,栈中要不为空。所以每次弹栈的前提都是要栈不为空。
看代码
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 。
感谢大佬观看,如有问题,烦请指点一二,感谢。
|