题目:
请根据每日气温列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用0来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
分析:
要想观测到更高的气温,至少需要等待的天数。也就是说在某一天想要观测到比这天更高的温度,至少要等待的天数,分析这句话提出重点:
1、一定是这天之后的某一天的气温;
2、之后的某一天的气温一定要大于这天的气温;
3、“至少”说明了只要在这天之后大于这天的气温并且是离这天最近的某一天;
给定的是一个数组,每个元素代表了每一天的气温,本质就是求数组的某个元素的索引与下一个比它大的且离它最近的元素的索引的差值,索引的差值就代表的是距离,也就是要等待的天数。一定要注意是下一个更大元素而不是最大。
此时我们可以遍历数组,同时借助于栈结构,将访问的元素的索引值压入栈中。从数组的第一个元素开始遍历,因为第一个元素之前是没有任何元素的,所以它不进行其他的操作,直接将其索引值入栈,然后从第二个元素开始遍历,此时栈顶元素是第一个元素的索引,而正在遍历的元素是第二元素,符合“下一个”这个条件,此时要判断当前正在遍历的元素是否大于栈顶索引指向的元素:
如果大于那么就将栈顶元素出栈,同时计算栈顶索引值与当前索引值的大小作为距离存入结果数组,这个距离值也正是结果数组中栈顶索引值所代表的结果值。
如果不大于,那么说明当前访问的元素值不大于栈顶索引值指向的元素值,此时就将当前元素的索引压入栈,继续向后遍历。也就是说栈中存储的索引值一定是在当前访问的元素的索引值前面的。
一旦有当前访问的元素值大于栈顶元素值时,我们要考虑到,栈中元素可能是多个的,所以我们要将栈中所有小于当前值的值的索引都出栈,这样才能保证,每个之前的元素都能找到其“下一个更大的元素”。
代码实现:
public int[] dailyTemperatures(int[] T) { if ( T == null ){ return null; } int[] res = new int[T.length]; if ( T.length == 0 ){ return res; } Stack<Integer> stack = new Stack<>(); for (int i = 0; i < T.length; i++) { while ( !stack.isEmpty() && T[i] > T[stack.peek()]){ Integer preindex = stack.pop(); res[preindex] = i - preindex; } stack.push(i); } return res; }
题目:
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
分析:
与上面的解法几乎一样,存在的区别在于,给的数组是循环数组,这个循环可以通过两次遍历+取模运算来解决,因为这个数组中的所有元素的“下一个最大元素”通过两次从左到右的遍历一定都可以求出来。为了方便结果数组的初始化值应全为-1;
实现的代码:
public int[] nextGreaterElements(int[] nums) { int[] res = new int[nums.length]; if ( nums == null ){ return nums; } if ( nums.length == 0 ){ return res; } Arrays.fill(res,-1); Stack<Integer> stack = new Stack<>(); for (int i = 0; i < 2 * nums.length; i++) { while ( !stack.isEmpty() && nums[i % nums.length] > nums[stack.peek()]){ Integer index = stack.pop(); res[index] = nums[i]; } if ( i < nums.length ){ stack.push(i); } } return res; }