题目
每日温度
请根据每日气温列表,重新生成一个列表,对应的位置的输出为:要想观测到更高的气温,至少需要等待的天数.如果气温在这之后都不再升高,则该位置用0代替.
例如,给定一个列表[73, 74, 65, 80,]
你的输出应该是[1, 2, 1, 0]
思路
首先,我们先来画图分析一下,毕竟图形是最直观的,温度列表数组如下图:
根据图形,先摒弃任何算法思想,直观的说一下,按照题目的要求,输出结果应该是啥
应该是:【1 天,2 天,1 天,0 天】
怎么算的呢?
其实很好算,但凡跟数组相关的,基本上都要利用数组下标,我们套一下
- 1 天 = 74温度的下标 1 减去 73 温度的下标 0 = (1 - 0)
- 2 天 = 80温度的下标 3 减去 74 温度的下标 1 = (3 - 1)
- 1 天 = 80温度的下标 3 减去 65 温度的下标 2 = (3 - 2)
- 0 天 = 80 温度是最后一个了,所以为 0
当计算当前温度需要等待的天数时,必须要等到下一轮或者后面好几轮才能得到结果。
比如:
- 当计算 温度 73 需要等待的天数时,等到第 2 轮循环时,就可以得到了;
- 当计算 温度 74 需要等待的天数时,等到第 4 轮循环时,才能得到;
- 当计算 温度 65 需要等待的天数时,等到第 4 轮循环时,才能得到;
可以看到,第 4 轮循环,可以计算出前面温度 65 和温度 74 的结果。
也就是说,需要有一个数据结构来保存当前温度的数组下标,以便后续的计算。
再画图来推导下。
我们初始化一个数组来保存计算的结果,默认都是 0。
【第一轮循环】
在第一轮循环时,数据结构是空的,没有计算,所以只是把温度 73 的下标存入了数据结构中。
【第二轮循环】
在第二轮循环时,数据结构保存了 0(温度 73 的下标),且本轮的温度 74,大于数据结构中的下标所代表的温度值 73,所以计算 (1 - 0 = 1),将温度 73 的结果赋值为 1,同时将下标 0 删除,下标 1 存入数据结构。
【第三轮循环】
在第三轮循环时,虽然数据结构不为空(里面有个下标 1),但是本次的温度 65,小于下标 1 所代表的温度 74,所以不参与计算,仅把下标 2 存入数据结构。
【第四轮循环】
在第四轮循环时,此时数据结构中下标为 2 和 1,本轮是温度 80。
而温度 80 大于下标 2 代表的温度 65,参与计算(3 - 2 = 1),所以温度 65 的结果为 1,删除下标 2;
接着再判断温度 80 大于下标 1 代表的温度 74,参与计算(3 - 1 = 2),所以温度 74 的结果为 2,删除下标 1;
最后将下标 3 存入数据结构。
【总结】
从上面的推导过程,可以看出来,我们需要一个数据结构来保存温度下标,且按照先进后出
的顺序,什么数据结构符合先进后出呢?
而且,只要这个下标参与了计算,就要把它从数据结构中弹出去。
代码实现
public int[] dailyTemperatures(int[] tmp){
Stack<Integer> stack = new Stack<>();
int[] res = new int[tmp.length]; //结果数组
for (int i = 0; i < tmp.length; i++) { //循环遍历气温
//如果栈非空,且当前气温tmp[i] 大于 栈顶温度,则将结果存入res
while (!stack.isEmpty() && tmp[i] > tmp[stack.peek()]){
Integer pop = stack.pop(); //弹出来的是 气温在数组中的下标
res[pop] = i - pop; //需要等待的天数为:当前下标-栈顶元素下标
}
stack.push(i); //气温入栈,注意存的是气温在数组中的下标
}
return res;
}
当然,也可以用暴力解法
public int[] dailyTemperatures2(int[] tmp){
int[] res = new int[tmp.length];
for (int i = 0; i < tmp.length; i++) {
for (int j = i + 1; j < tmp.length; j++) {
if (tmp[j] > tmp[i]){
res[i] = j - i;
break;
}
}
}
return res;
}