每日温度
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
思路1:利用栈
该题其实是利用栈寻找左右第一个比它大的数的一个变种
其实,题目就是想求右边某一元素a的右边,第一个比a大的元素b距离a的距离
这不就是,找出右边第一个比它大的值一样么
class Solution {
public int[] dailyTemperatures(int[] T) {
//先写边界值
if(T == null || T.length == 0) return null;
//数组里面放索引
int[] rightArray = new int[T.length];
//保持栈,从栈底到栈顶是单调递减的
Stack<Integer> stack = new Stack<Integer>();
//扫描一遍数组
for(int i = 0; i < T.length; i++)
{
//> 而非 >=
while (!stack.empty() && T[i] > T[stack.peek()])
{
rightArray[stack.peek()] = i - stack.peek();
stack.pop();
}
stack.push(i);
}
return rightArray;
}
}
思路2:倒推法
该思路属于动态规划
由已知,推出未知
首先可以确定的是,最后一个元素的天数肯定为0,因为,后面已经没有了。
然后再看倒数第二个
如果倒数第二个的值,比倒数第一个的值大,则倒数第二个值的天数是0
如果倒数第二个的值,比倒数第一个的值小,则倒数第二个值的天数是1
…
依次类推
换成伪代码是:
i用来扫描所有的元素,从右往左扫描(i逐渐递减),一开始i指向倒数第2个元素
对于每一个j,一开始令j = i + 1;
- 如果T[i] < T[j],那么values[i] = j - i,然后i --;
- T[i] == T[j]
2.1 如果values[j] = 0;那么,values[i] = 0,然后i --;
2.2 如果values[j] != 0;那么,values[i] = values[j] + j - i,然后i --; - 如果T[i] > T[j]
3.1 如果values[j] = 0;那么,values[i] = 0,然后i --;
3.2 如果values[j] != 0;那么,j = j + values[j],然后重新进入第一步;
class Solution {
public int[] dailyTemperatures(int[] T) {
//先写边界值
if(T == null || T.length == 0) return null;
int[] valuesArray = new int[T.length];
valuesArray[T.length - 1] = 0;
for(int i = T.length - 2; i >= 0; i--)
{
int j = i + 1;
while(true){
if(T[i] < T[j]){
valuesArray[i] = j - i;
break;
}else if(T[i] == T[j]){
if(valuesArray[j] == 0){
valuesArray[i] = 0;
}else{
//相等,但是两个不一样挨着,所以必须j - i
valuesArray[i] = valuesArray[j] + j - i;
}
break;
}else{//T[i] > T[j]
if(valuesArray[j] == 0){
valuesArray[i] = 0;
break;
}else{
j = j + valuesArray[j];
}
}
}
}
return valuesArray;
}
}
需要注意的地方:
虽然在定义的时候,int j = i + 1;
但是,在所有求i与j的距离的时候,不能直接使用1
必须使用j - i,这是因为,有可能是3.2的情况,j已经变了
另外,由于3.2需要进行循环,所以从1开始,就是一个循环
巧妙运用break,结束循环,使得在正常情况下循环只执行一次,而只有在3.2的时候循环才执行