739.每日温度 496.下一个更大元素 I
739.每日温度
力扣题目链接(opens new window)
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
思路
思路:单调栈
题目的暴力算法很好想,双重for循环遍历即可,这里就不多介绍了。介绍下单调栈思路
所谓单调栈,就是栈内元素单调。要么递增要么递减。那么单调栈的使用场景是什么呢?
通常是一维数组,要寻找任意元素,左右两边第一个比其大或者比其小的元素位置,就可用单调栈
本题目是找到当前元素右侧第一个比其大元素位置,可用单调栈思路
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
使用单调栈注意两点
1.单调栈内存储数组元素下标
2.单调栈内存储元素的顺序如何确认?这里指的顺序【从栈头到栈底的顺序】。对于本题目要使用递增循序(再强调一下是指从栈头到栈底的顺序),
即如果求元素右边第一个比其大的元素位置,那么单调栈递增。求元素右边第一个比其小的元素位置,那么单调栈递减。
使用单调栈主要有三个判断条件。
-当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
-当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
-当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
看文字不太好理解这三个判断条件,举例画图理解。temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。首先先将第一个遍历元素加入单调栈
加入T[1] = 74,因为T[1] > T[0](当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况)。
我们要保持一个递增单调栈(从栈头到栈底),所以将T[0]弹出,T[1]加入,此时result数组可以记录了,result[0] = 1,即T[0]右面第一个比T[0]大的元素是T[1]。
加入T[2],同理,T[1]弹出
加入T[3],T[3] < T[2] (当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况),加T[3]加入单调栈。
加入T[4],T[4] == T[3] (当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!
加入T[5],T[5] > T[4] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[4]弹出,同时计算距离,更新result
T[4]弹出之后, T[5] > T[3] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[3]继续弹出,同时计算距离,更新result
直到发现T[5]小于T[st.top()],终止弹出,将T[5]加入单调栈
加入T[6],同理,需要将栈里的T[5],T[2]弹出
同理,继续弹出
此时栈里只剩下了T[6]
加入T[7], T[7] < T[6] 直接入栈,这就是最后的情况,result数组也更新完了。
此时有同学可能就疑惑了,那result[6] , result[7]怎么没更新啊,元素也一直在栈里。
其实定义result数组的时候,就应该直接初始化为0,如果result没有更新,说明这个元素右面没有更大的了,也就是为0。
时间复杂度:O(n)
空间复杂度:O(n)
代码如下
public static void main(String args[]) {
int[] temperatures = new int[]{73, 74, 75, 71, 69, 72, 76, 73};
dailyTemperatures(temperatures);
}
public static int[] dailyTemperatures(int[] temperatures) {
if (temperatures == null)
return null;
int[] result = new int[temperatures.length];
Stack<Integer> stack = new Stack<>();// 单调递增(从栈头到栈底),存储数组元素下标
stack.push(0);
for (int i = 1; i < temperatures.length; i++) {
int topElement = stack.peek();
while (temperatures[i] > temperatures[topElement]) {
Integer dropElement = stack.pop();
result[dropElement] = i - dropElement;
if (stack.isEmpty()) {// 栈内无元素可出栈
break;
}
topElement = stack.peek();
}
stack.push(i);
}
return result;
}
496.下一个更大元素 I
力扣题目链接(opens new window)
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
示例 2:
输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出-1 。
提示:
- 1 <= nums1.length <= nums2.length <= 1000
- 0 <= nums1[i], nums2[i] <= 10^4
- nums1和nums2中所有整数 互不相同
- nums1 中的所有整数同样出现在 nums2 中
思路
单调栈
本题目和【739. 每日温度】一样均使用单调栈解决,但要处理nums1和nums2之间映射关系,导致本题难度偏高一些
如果做过【739. 每日温度】,那么求出Nums2的每个元素在 nums2 中的下一个比其大的值,还是很简单的
题目要求找出 nums1 中每个元素在 nums2 中的下一个比其大的值。两者之间映射关系如何确定呢?我第一次做也搞不明白怎么映射。看了下题解可以使用hashMap
使用map的key存储nums[i],value存储i.根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。
题目说如果不存在对应位置就输出 -1 ,所以定义的result数组如果某位置没有被赋值,那么就应该是是-1,所以就初始化为-1。
时间复杂度:O(n)
空间复杂度:O(n)
代码如下
public static void main(String args[]) {
int[] nums1 = new int[]{4, 1, 2};
int[] nums2 = new int[]{1, 3, 4, 2};
nextGreaterElement(nums1, nums2);
}
public static int[] nextGreaterElement(int[] nums1, int[] nums2) {
if (nums1 == null || nums2 == null)
return null;
Map<Integer, Integer> map = new HashMap<>();// 保存nums1的value 和下标i
for (int i = 0; i < nums1.length; i++) {
map.put(nums1[i], i);
}
int[] nums1Result = new int[nums1.length];// 保存Nums1每一个元素右侧第一个比其大的元素value
// 初始化value为-1
Arrays.fill(nums1Result, -1);
Stack<Integer> stack = new Stack<>();
stack.push(0);
for (int i = 1; i < nums2.length; i++) {
int stackTop = stack.peek();
while (nums2[i] > nums2[stackTop]) {
stackTop = stack.pop();
if (map.containsKey(nums2[stackTop])) {
nums1Result[map.get(nums2[stackTop])] = nums2[i];
}
if (stack.isEmpty())
break;
stackTop = stack.peek();
}
stack.push(i);
}
return nums1Result;
}