1、问题描述
根据每日的气温列表,生成一个新的列表。新列表中每个位置的元素表示从当天开始到下一次温度升高需要等待的天数。例如,温度列表是[73,74,75,71,69,72,76,73],那么产生的新的列表是[1,1,4,2,1,1,0,0]。
注意:数组 temperatures 的长度范围: [1, 30000]. 每个温度的范围: [30, 100].
2、解题思路
- 思路1:最简单的方法,是使用双重循环,第一层循环负责遍历列表中的每一个元素,第二个循环负责从第一层循环当前遍历的元素后面找到首个大于当前遍历元素的元素,然后将这两个元素的索引相减,得到的结果即为当前天需要等待的天数。这种方法的时间复杂度为 O ( n 2 ) O(n^{2}) O(n2)。
- 思路2:我们逆序遍历数组,看如何生成新的列表。以[73,74,75,71,69,72,76,73]为例,假设新生成的列表为wait:
- 很明显,最后一天需要等待的天数一定是0,所以wait[7]=0;
- 再看倒数第二天,将他和最后一天比较,76>73,后面不可能会有温度升高,所以wait[6]=0;
- 倒数第三天,先和倒数第二天比较, 72<76,只需要等待一天温度就会升高,所以wait[5]=1;
- 倒数第四天,先和倒数第三天比较,69<72,只需等待一天温度就会升高,所以wait[4]=1;
- 倒数第五天,先和倒数第四天比较,71 > 69,然后再和倒数第三天比较,71 < 72,所以wait[3]=2;
- 倒数第六天,先和倒数第五天比较,75>71,再和倒数第四天比较,75>69,接着和倒数第三天比较,75>72,最后再和倒数第二天比较,75<76,所以wait[2]=4;
- 其他类似。
- 在上面这个例子,我们可以使用栈来存储需要和当前遍历元素进行元素进行比较的元素的索引,栈的栈底到栈顶是一个非递增的序列,即栈维持的是一个非递增序列,接下来我们看看使用了栈之后的步骤:
步骤 | 操作 | 栈的情况 | 相应的wait值 |
---|---|---|---|
1 | 压入7 | [7] | 0 |
2 | t[6] > t[s.top]=t[7],弹出栈顶 | [] | 0 |
3 | 压入6 | [6] | 0 |
4 | t[5] < t[s.top]=t[6],压入5 | [6,5] | 6-5=1 |
5 | t[4] < t[s.top]=t[5],压入4 | [6,5,4] | 5-4=1 |
6 | t[3] > t[s.top]=t[4],弹出栈顶 | [6,5] | |
7 | t[3] < t[s.top]=t[5],压入3 | [6,5,3] | 5-3=2 |
8 | t[2] > t[s.top]=t[3],弹出栈顶 | [6,5] | |
9 | t[2] > t[s.top]=t[5],弹出栈顶 | [6] | |
10 | t[2] < t[s.top]=t[6],压入2 | [6,2] | 6-2=4 |
… | … | … | … |
总结归纳就是:初始时,将列表倒数第一个元素的索引压入栈中,并且将新列表对应位置的wait值设为0,接着从倒数第2天开始逆序遍历列表,若当前遍历元素大于或等于栈顶,则将栈顶元素弹出,直到栈顶元素大于当前遍历元素为止,如果栈中的元素全部弹出为空后仍没有找到大于当前遍历元素,那么新列表对应位置的wait值设为0,如果栈不为空,则新列表对应位置的wait值为栈顶元素减去当前遍历元素的索引。之后压入当前遍历元素。
3、代码实现
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
if len(T) == 0:
return []
result = [0] * len(T)
stack = []
stack.append(len(T)-1)
for i in range(1,len(T)):
ind = len(T) - 1 - i
while len(stack)!= 0 and T[ind] >= T[stack[-1]]:
stack.pop()
if len(stack) != 0:
result[ind] = stack[-1] - ind
stack.append(ind)
return result