题目
leetcode 739
题目链接:link.
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
分析
题目写的很花里胡哨,但是究其本质,就是要找每个数与下一个比它大的数的距离,如果后面没有比它大的数,结果就为0。
题解
暴力求解
看完题目,很容易就想到暴力求解,使用双重循环,实现很容易,但是时间空间都浪费了。代码如下:
public static int[] dailyTemperatures(int[] T) {
int[] result = new int[T.length];
for (int i = 0; i < T.length; i++) {
for(int j = i; j < T.length; j++) {
if(T[j]>T[i]){
result[i] = j-i;
break; // 找到之后就直接break
}
if(j == T.length-1 && T[j]<=T[i]) break;
}
}
return result;
}
递减栈
写完暴力法,很久都没有想到有啥其他方法(还是我菜),后来看了一下题解,一看到递减栈三个字,恍然大悟,实现下来也不难,但是只需要一次循环,时间复杂的O(n),代码如下:
// 维护一个递减栈,上面的数始终比下面的数小,
// 栈里只用存数的序号,每次遍历到一个数,
// 从栈顶向栈底依次比较,碰到比本数大的数就将本数入栈
public static int[] dailyTemperatures(int[] T){
if (T == null || T.length == 0) return new int[0];
Stack<Integer> stack = new Stack<>();
int[] result = new int[T.length];
for (int i = 0; i < T.length; i++) {
while(!stack.empty() && T[i] > T[stack.peek()]){
int index = stack.pop();
result[index] = i - index;
}
stack.push(i);
}
return result;
}
暴力求解改进
暴力求解的问题就是没有用到前面获得的数据,这个改进从后往前遍历,这样每次向后搜寻的时候,可以利用已经获得的信息进行跳过一些无用的循环,用时缩短很多,超过90+%。代码如下:
public static int[] dailyTemperatures(int[] T){
int[] result = new int[T.length];
for (int i = T.length-2; i >=0 ; i--) { //从后往前
int j = i+1;
while (j < T.length){
if(T[j]>T[i]){ // 大于直接设置结果
result[i] = j-i;
break;
}
else if(result[j]==0){ // 此时j <= i,并且j后没有比j大的值,那么一定没有比i大的值,直接设为0
break;
}
else{
j += result[j]; // 跳跃到下一个较大值,节省时间
}
}
}
return result;
}
总结
这个题不算很难,主要题解还是使用递减栈,只是比较难想到(可能是因为我菜吧),至于第三种方法还是比较好理解的,就是一个小小的优化,但是时间上的提升很大。