跳至主要內容

单调队列

大约 2 分钟

单调队列

题目难度
239. 滑动窗口最大值open in new window困难
1438. 绝对差不超过限制的最长连续子数组open in new window困难滑动窗口内最大最小值
2398. 预算内的最多机器人数目open in new window困难滑动窗口内最大值

java.util.Deque

Deque:

First Element (Head)Last Element (Tail)
Throws exceptionSpecial valueThrows exceptionSpecial value
InsertaddFirst(e)offerFirst(e)addLast(e)offerLast(e)
RemoveremoveFirst()pollFirst()removeLast()pollLast()
ExaminegetFirst()peekFirst()getLast()peekLast()

Queue:

Queue MethodEquivalent Deque Method
add(e)addLast(e)
推荐offer(e)offerLast(e)
remove()removeFirst()
推荐poll()pollFirst()
element()getFirst()
推荐peek()peekFirst()

Stack:

Stack MethodEquivalent Deque Method
入栈push(e)addFirst(e)
出栈pop()removeFirst()
栈顶元素peek()getFirst()

239. 滑动窗口最大值

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution239 {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int len = nums.length;

        // 前 k 个
        Deque<Integer> deque = new ArrayDeque<>();
        for (int i = 0; i < k; i++) {
            while (!deque.isEmpty() && nums[i] >= nums[deque.getLast()]) {
                deque.removeLast();
            }
            deque.addLast(i);
        }

        int[] res = new int[len - k + 1];
        res[0] = nums[deque.getFirst()];

        // k+1 到 len
        for (int i = k; i < len; i++) {
            while (!deque.isEmpty() && nums[i] >= nums[deque.getLast()]) {
                deque.removeLast();
            }
            deque.addLast(i);

            while (deque.getFirst() <= i - k) {
                deque.removeFirst();
            }
            res[i - k + 1] = nums[deque.getFirst()];
        }
        return res;
    }
}

1438. 绝对差不超过限制的最长连续子数组

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution1438 {
    public int longestSubarray(int[] nums, int limit) {
        int len = nums.length;

        Deque<Integer> deque1 = new ArrayDeque<>();
        Deque<Integer> deque2 = new ArrayDeque<>();

        int max = 0;
        // 双指针
        int left = 0;
        int right = 0;
        while (right < len) {
            // 滑动窗口最大值
            while (!deque1.isEmpty() && nums[right] > deque1.getLast()) {
                deque1.removeLast();
            }
            deque1.addLast(nums[right]);
            // 滑动窗口最小值
            while (!deque2.isEmpty() && nums[right] < deque2.getLast()) {
                deque2.removeLast();
            }
            deque2.addLast(nums[right]);

            // 左指针右移
            while (!deque1.isEmpty() && !deque2.isEmpty()
                    && deque1.getFirst() - deque2.getFirst() > limit) {
                if (nums[left] == deque1.getFirst()) {
                    deque1.removeFirst();
                }
                if (nums[left] == deque2.getFirst()) {
                    deque2.removeFirst();
                }
                left++;
            }

            max = Math.max(max, right - left + 1);
            right++;
        }
        return max;
    }
}

2398. 预算内的最多机器人数目

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution2398 {
    public int maximumRobots(int[] chargeTimes, int[] runningCosts, long budget) {
        int n = chargeTimes.length;

        int left = 1;
        int right = n + 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            // 边界二分 F, F,..., F, [T, T,..., T]
            // ----------------------^
            if (!checkMid(chargeTimes, runningCosts, budget, mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left - 1;
    }

    // true: 可以连续运行 k 个机器人
    private boolean checkMid(int[] chargeTimes, int[] runningCosts, long budget, int k) {
        int n = chargeTimes.length;

        // 滑动窗口最大值
        Deque<Integer> deque = new ArrayDeque<>();
        long max = 0;
        long sum = 0;

        // 前 k 个
        for (int i = 0; i < k; i++) {
            while (!deque.isEmpty() && chargeTimes[i] >= chargeTimes[deque.getLast()]) {
                deque.removeLast();
            }
            deque.addLast(i);
            sum += runningCosts[i];
        }

        max = chargeTimes[deque.getFirst()];
        if (max + k * sum <= budget) {
            return true;
        }

        // k+1 到 len
        for (int i = k; i < n; i++) {
            while (!deque.isEmpty() && chargeTimes[i] >= chargeTimes[deque.getLast()]) {
                deque.removeLast();
            }
            deque.addLast(i);
            while (deque.getFirst() <= i - k) {
                deque.removeFirst();
            }

            max = chargeTimes[deque.getFirst()];
            sum = sum + runningCosts[i] - runningCosts[i - k];

            long totalCost = max + k * sum;
            if (totalCost <= budget) {
                return true;
            }
        }
        return false;
    }
}

(全文完)