单调栈的初次使用
输入:
nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:
[-1,3,-1]
解释:
对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。
对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。
对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。
之前有遇到过类似这样的问题,都是关于求数组更大元素的问题,当时并不太清楚单调栈的使用,而是通过暴力解法对数组疯狂遍历,最后才得到数组每个位置对应更大元素位置
对于此类问题,用单调栈的思路去解决是比较容易的。
在这个题的思路,尽量在对nums2数组一次遍历后能够得到一个result集合(将每个位置对应的更大元素得到),对于每个当前元素应该关注它的右边元素。每次将小的元素压入栈中,出现更大的元素则是栈顶元素对应的更大值。
单调栈的细节:小的应该被pop,大的还要push进栈中,这样可以保持栈的单调性。
具体操作:我们首先把第一个元素 nums2[1] 放入栈,随后对于第二个元素 nums2[2],如果 nums2[2] > nums2[1],那么我们就找到了 nums2[1] 的下一个更大元素 nums2[2],此时就可以把 nums2[1] 出栈并把 nums2[2] 入栈;如果 nums2[2] <= nums2[1],我们就仅把 nums2[2] 入栈。对于第三个元素 nums2[3],此时栈中有若干个元素,那么所有比 nums2[3] 小的元素都找到了下一个更大元素(即 nums2[3]),因此可以出栈,在这之后,我们将 nums2[3] 入栈,以此类推。
代码实现
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map<Integer, Integer> reuslt = new HashMap<Integer, Integer>();
Stack<Integer> stacks = new Stack<>();
for(int i = 0;i < nums2.length ; i++) {
while(!stacks.empty() && nums2[i] > stacks.peek()) {
reuslt.put(stacks.pop(),nums2[i]);
}
stacks.push(nums2[i]);
}
while(!stacks.empty()) {
reuslt.put(stacks.pop(), -1);
}
for(int i = 0 ; i < nums1.length;i++ ) {
nums1[i] = reuslt.get(nums1[i]);
}
return nums1;
}
时间复杂度:O(M+N),其中 M 和 N分别是数组 nums1 和 nums2 的长度。
空间复杂度:O(N)。我们在遍历 nums2 时,需要使用栈,以及哈希映射用来临时存储答案。
这个题最优解肯定并不是使用单调栈的方式实现,但是关于单调栈的思想是比较适合解决对这类问题的