思路: 这两题都是单调栈问题,在遍历的时候使用单调栈来降低时间复杂度,每日气温一看题意就是能使用双重for进行暴力求解的题目,时间复杂度为n的二次方,当然在一道中等的题目上暴力肯定是会超时的,题目本质上是对一维数组,要寻找任一个元素的右边第一个比自己大的元素的位置,这一类问题常使用单调栈进行优化(如左边第一个比自己小的元素等类似的问题也可以用单调栈,只不过使用的单调栈增减顺序可能不同)
所以本题应当维护一个怎样的单调栈呢:依题意我们要求右边第一个比自己大的元素的位置,那么在遍历的时候遇到的元素比栈顶元素大的时候就应该把遍历到的元素加入栈中,也就是单调栈的顺序应该是从栈顶到栈底单调递增的,同样为了求元素的位置,遍历的时候加入栈的元素应当是数组的下标而不是原始值。具体流程如下:
当遍历到的i对应的数组元素比栈顶i对应的数组元素小的时候 就把当前i也加入栈中
相反,如果更大 则将当前i与栈顶i的差值记录到res数组的相应位置 并弹出栈顶i 对新的栈顶i重复判断和操作 直到不满足条件
(遍历到的i如果对应值很大 那么其可能会是很多个元素的“右边的第一个更大的值” 所以要用while进行重复的判断)
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
// 超时
// int[] tem = new int[temperatures.length];
// for (int i = 0; i < temperatures.length - 1; i++) {
// for (int j = i+1; j < temperatures.length ; j++) {
// if (temperatures[j] > temperatures[i]){
// tem[i] = j-i;
// break;
// }
// }
// }
// return tem;
int[] res = new int[temperatures.length];
Deque<Integer> deque = new LinkedList<>();
/**
*用单调栈在一次循环中计算右边的第一个更大的值
*依照题意 放入单调栈中的应当是数组的下标 当遍历到的i对应的数组元素比栈顶i对应的数组元素小的时候 就把当前i也加入栈中
* 相反,如果更大 则将当前i与栈顶i的差值记录到res数组的相应位置 并弹出栈顶i 对新的栈顶i重复判断和操作 直到不满足条件
* (遍历到的i如果对应值很大 那么其可能会是很多个元素的“右边的第一个更大的值” 所以要用while进行重复的判断)
*
*/
// deque.push(0);
for (int i = 0; i < temperatures.length; i++){
while (!deque.isEmpty() &&temperatures[i] >temperatures[deque.peek()]){
res[deque.peek()] = i - deque.peek();
deque.pop();
}
deque.push(i);
}
return res;
}
}
下一个元素I 思路:这题本质上和每日气温是一样的,计算nums1的元素在nums2对应元素位置的下一个最大元素。由于nums1是nums2的子集,也就是nums1中的每一个元素都会在nums2中出现,而nums2的元素不一定会在nums1中出现,我们只需要在遍历nums2的时候判断该元素是否在nums1中,从而决定是否寻找该元素的下一个最大元素即可,所以我们需要用hashmap记录nums1元素,方便判断是否出现在nums2中,同时本题求的是最大元素而不是最大元素的位置 ,注意这两点即可
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
/**
* 本质上和每日温度是一样的 只不过是遍历的数组中部分需要进行下一个更大元素的计算
*/
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums1.length; i++) {
map.put(nums1[i],i );
}
int[] res = new int[nums1.length];
Arrays.fill(res,-1);
Deque<Integer> stack = new LinkedList<>();
for (int i = 0; i < nums2.length; i++) {
// 单调栈 栈顶到栈底是递增的
while (!stack.isEmpty() && nums2[stack.peek()] < nums2[i]){
int pre = nums2[stack.pop()];
// 判断当前的这个栈顶元素是否需要计算下一个最大值 即是否在nums1中
if (map.containsKey(pre)){
// 记录下一个最大元素的值
res[map.get(pre)] = nums2[i];
}
}
stack.push(i);
}
return res;
}
}