单调栈 & 单调队列

单调栈(Monotonic Stack)

单调栈:本质上还是一个先进后出的栈结构,但是在将元素压入栈中时,需要保持栈内所有元素具有单调性(单调递增/单调递减)

单调栈的核心功能需求:添加元素时要保证栈中的数据呈现单调性。

public class MonotonicStack {
    Stack<Integer> stack = new Stack<>();

    // 保证单调递减
    public void push(int num) {
        while (!stack.isEmpty() && stack.peek() < num) {
            stack.pop();
        }

        stack.push(num);
    }

    // 弹出栈顶元素
    public void pop() {
        stack.pop();
    }

    // 返回栈顶元素
    public int peek() {
        return stack.peek();
    }
    
    public boolean isEmpty() {
        return stack.isEmpty();
    }
}

单调栈应用场景:下一个更大元素,即输入一个数组,返回一个等长的数组,对应索引位置存储着下一个更大的元素值,如果下一个更大元素不存在,则存储-1

该问题就可以直接利用上述单调栈的数据结构:

public int[] nextGreatElement(int[] nums) {
    int[] ans = new int[nums.length];
    int idx = nums.length - 1;

    for (int i = nums.length - 1; i >= 0; i--) {
        ans[idx--] = monotonicStack.isEmpty() ? -1 : monotonicStack.peek();
        monotonicStack.push(nums[i]);
    }

    return ans;
}

单调队列(Monotonic Queue)

单调队列和单调栈是非常相似的,只是一个本质上是队列,一个本质上是栈,扩增的需求都是需要保证队列内或栈内元素的单调性。

单调队列功能需求:

  • push()方法:队尾添加元素,但是在添加时需要删除队列中小于/大于当前元素的其他元素,以保证队列中数据呈现单调增大/单调减小

  • pop()方法:队头删除元素

  • max()方法:返回队列中的最大值

  • min()方法:返回队列中的最小值

public class MonotonicQueue {
    // 用双向链表维护一个队列
    private LinkedList<Integer> queue = new LinkedList<>();

    // 保证队列是单调递减的
    public void push(int num) {
        while (!queue.isEmpty() && queue.getLast() < num) {
            queue.pollLast();
        }

        queue.addLast(num);
    }

    // 弹出指定队头元素
    public void pop(int num) {
        if (num == queue.getFirst()) {
            queue.pollFirst();
        }
    }

    // 返回队头元素, 即队列中的最大值
    public int max() {
        return queue.getFirst();
    }

    // 返回队尾元素, 即队列中的最小值
    public int min() {
        return queue.getLast();
    }

单调队列应用场景:滑动窗口最大值,即输入一个数组和滑动窗口的大小,该滑动窗口在数组上从左至右滑动,输出滑动过程中窗口内元素的最大值。

public int[] maxSlidingWindow(int[] nums, int k) {
    int[] ans = new int[nums.length - k + 1];
    int idx = 0;
    for (int i = 0; i < k; i++) {
        if (i < k - 1) {
            monotonicQueue.push(nums[i]);
        }
        else {
            monotonicQueue.push(nums[i]);
            ans[idx++] = monotonicQueue.max();
            monotonicQueue.pop(nums[i - k + 1]);
        }
    }

    return ans;
}
posted @ 2023-07-03 03:13  ylyzty  阅读(20)  评论(0编辑  收藏  举报