【算法修炼】单调栈

单调栈

      • 一、下一个更大元素Ⅰ(简单)
      • 二、下一个更大元素Ⅱ(中等)
      • 三、每日温度
      • 四、接雨水(困难)

单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)。

听起来有点像堆(heap)?不是的,单调栈用途不太广泛,只处理一种典型的问题,叫做 Next Greater Element。

一、下一个更大元素Ⅰ(简单)

下一个更大元素Ⅰ
【算法修炼】单调栈_第1张图片
用这个图更方便理解,从数组最后一个元素开始遍历,判断该元素与栈顶元素大小,如果栈顶小于等于当前数,出栈,继续遍历栈,直到找到第一个大于该元素的值。如果栈都为空了,说明没找到,结果-1。

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        Stack<Integer> stack = new Stack<>();
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = nums2.length - 1; i >= 0; i--) {
            // 注意一定从数组尾部开始遍历入栈
            // peek是取栈顶
            while (!stack.isEmpty() && stack.peek() <= nums2[i]) {
                // 弹出
                stack.pop();
            }
            if (stack.isEmpty()) {
                map.put(nums2[i], -1);
            } else {
                map.put(nums2[i], stack.peek());
            }
            // 入栈
            stack.push(nums2[i]);
        }

        for (int i = 0; i < nums1.length; i++) {
            nums1[i] = map.get(nums1[i]);
        }
        return nums1;
    }
}

二、下一个更大元素Ⅱ(中等)

改编题,加了条件:数组是可循环遍历的。

为了实现数组的循环遍历,常见的办法是再增加同样一个数组,使得数组长度为2n。也可以不增加数组,假装数组长度为2n,使用取模来实现循环遍历。

例如:1 2 3 4 5,n=5

for (int i = 0; i < 2 * n; i++) {
	print(nums[i % n]);
	// 当 i = n时,刚好循环到第一个元素
}

对于本题,在单调栈模板的基础上加上循环遍历即可。

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        Stack<Integer> stack = new Stack<>();
        int n = nums.length;
        int[] ans = new int[n];
        for (int i = 2 * n - 1; i >= 0; i--) {
            // 按照单调栈模板,同样从最后一个元素开始遍历
            while(!stack.isEmpty() && stack.peek() <= nums[i % n]) {
                stack.pop();
            }
            if (stack.isEmpty()) {
                ans[i % n] = -1;
            } else {
                ans[i % n] = stack.peek();
            }
            stack.push(nums[i % n]);
        }
        return ans;
    }
}

从2 * n - 1,那就是第二个重复数组的最后一个元素开始遍历,就可以保证整个数组的元素是可以循
环遍历的。

三、每日温度

每日温度
需要注意的是,这里存储下标,不是温度。

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;
        Stack<Integer> stack = new Stack<>();
        int[] ans = new int[n];
        for (int i = n - 1; i >= 0; i--) {
            while (!stack.isEmpty() && temperatures[stack.peek()] <= temperatures[i]){
                stack.pop();
            }
            if (stack.isEmpty()) {
                ans[i] = 0;
            } else {
                ans[i] = stack.peek() - i;
            }
            // 存下标!!
            stack.push(i);
        }
        return ans;
    }
}

单调找用于快速找到第一个大于该数的数,可以寻找左边也可以寻找右边,也可以循环查找。

四、接雨水(困难)

【算法修炼】单调栈_第2张图片

你可能感兴趣的:(算法修炼,算法,排序算法,leetcode)