题目
根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
算法
1、依次遍历
思想:依次从该判断位置后面的一位往后遍历到数组末尾进行比较,如果中甲找到目标值,则返回,否则遍历到数组末尾
public int[] dailyTemperatures(int[] T) {
int size=T.length;
int k=0;
int[] arr=new int[size];
while(k<size) {
int temp=T[k];
int n=0;
for(int i=k+1;i<size;i++) {
if(temp<T[i]) {
arr[k]=n+1;
break;
}else { //当不存在比该温度高得情况时
n+=1;
if(n==size-k) { //当遍历到最后一个温度仍没有找到高于该温度的温度时,返回0
arr[i]=0;
}
}
}
k++;
}
return arr;
}
第一次精简
else {
n+=1;
if(n==size-k) {
arr[i]=0;
}
}
将else条件判断删除,运行时间缩短一半,因为这个判断纯属多余。因为arr[]数组初始化就是0,找不到直接返回就可以了,不用再用一个条件语句判断将其置0。修改后得代码如下
public int[] dailyTemperatures(int[] T) {
int size=T.length;
int[] arr=new int[size];
for(int k=0;k<size;k++) { //将while语句换成for语句
int temp=T[k];
int n=0;
for(int i=k+1;i<size;i++) {
if(temp<T[i]) {
arr[k]=n+1;
break;
}
n++;
}
}
return arr;
}
注意:1、删除一个条件判断分支else语句后,运行时间缩短一半
2、将while循环换成for循环后,时间缩短100多ms,具体原因不清楚,百度到的答案也说while循环和for循环得执行效率不相上下,执行效率主要取决于循环次数,甚至while循环得执行效率腰稍好于for循环。能用for循环时尽量用for循环
2、栈实现
运行时间84ms
思想:栈中存储的是数组中元素对应的索引值,其对应的元素值是依次递增的,遍历时采用反向遍历的方法,从后往前依次过滤掉无效的值。每次新的元素入栈时,栈顶值就是第一个大于该元素的元素索引值,只需要将栈顶元素索引值减去新元素索引值就是当前位置的arr[i]。
用数组 [73, 74, 75, 71, 69, 72, 76, 73]举例如下,为方便理解,将栈中索引值对应的元素值用()写在旁边:
i=7,stack(7,(73)),arr[i]=0;
i=6,stack(6,(76)),arr[i]=0;
//因为新元素76>73,为保证栈中索引对应的元素值递增性,应该先把栈顶元素弹出,再将新元素压入栈*
i=5,stack(5(72)6(76)),arr[i]=栈顶索引值6-当前索引值i=6-5=1;
//因为新元素72<73,符合栈中索引对应的元素值递增性,先进行计算arr[i]的值,再将新元素压入栈
i=4,stack(4(69),5(72)6(76)), arr[i]=5-i=1;
i=3,stack(3(71),5,72),6,(76)),arr[i]=5-i=2;
i=2,stack(2(75)6(76)), arr[i]=6-i=4;
i=1,stack(1(74) 2(75)6(76)), arr[i]=2-1=1;
i=0,stack(0(73) 1(74) 2(75)6(76)), arr[i]=1-0=1;
public int[] dailyTemperatures(int[] T) {
Stack<Integer> s=new Stack<>(); // 用于记录遇到的每个递增值得索引值
int size=T.length;
int[] arr=new int[size]; //初始化返回的数组
for(int i=size-1;i>=0;i--) { //反向遍历
while(!s.empty()&&T[i]>=T[s.peek()]) {//当前值大于栈顶值时,把栈顶的索引值弹出,
//直到能够保证栈中的元素是递增的
s.pop();
}
if(!s.empty()) { //当栈中的元素全部弹出时,说明
arr[i]=s.peek()-i;
}
/*
* if(s.empty()) { arr[i]=0; }else { arr[i]=s.peek()-i; }
*/
s.push(i); //将值仅次于栈顶索引值对应的数的索引值压入栈
}
return arr;
}
3、反向遍历实现
用时4ms
思想:反向求出每个元素对应的温度升高需要等待的天数,以数组T=[73, 74, 75, 71, 69, 72, 76, 73]为例:
1、i=7:T[i]73对应的arr[7]=0;
2、i=6:T[i]先跟T[i+1]比较,76>73,而没有再出现比73还大的数,所以arr[6]=0;
3、i=5:T[i]先跟T[i+1]比较,72<76,故arr[5]=1;
4、i=4:T[i]先跟T[i+1]比较,69<72,故arr[4]=1;
5、i=3:T[i]先跟T[i+1]比较,71>69,先定位到第一个比T[i+1]69大的数(因为大于69的数不一定大于71,但第一个大于69的数之前的数都是小于等于69的数,则一定小于71),69对应的索引值为4,则第一个比69大的数的索引值为:4+arr[4]=5,该索引值对应的数是72,71<72,所以arr[3]=5-3=2;
6、i=2:T[i]先跟T[i+1]比较,75>71,71的索引值为3,先定位到第一个大于71的数的位置为:3+arr[3]=5,该值为72,72<75,接着往下找出第一个大于72的值的位置为:5+arr[5]=6,该处的值为76,76>75,即arr[i]=6-i=4;
7、i=1:T[i]先跟T[i+1]比较,74<75,故arr[i]=1;
8、i=0:T[i]先跟T[i+1]比较,73<74,故arr[i]=1;
int size=T.length;
int[] arr=new int[size];
for(int i=size-2;i>=0;i--) {
for(int j=i+1;j<size;j+=arr[j]) { //直接定位到下一个大于T[j]的位置为j
if(T[i]<T[j]) {
arr[i]=j-i;
break;
}
if(arr[j]==0) { //当arr[j]=0时,即没有比T[j]大的数了
if(T[j]>T[i]) {//如果刚好这时T[j]>T[i]
arr[i]=j-i;
}
break; //如果到这儿都还没有找到大于T[i]的数,则不存在这个数,跳出循环
}
}
}
return arr;