跳至主要內容

单调栈

大约 2 分钟

单调栈

题目难度
907. 子数组的最小值之和open in new window中等数据范围 3*10^4
1508. 子数组和排序后的区间和open in new window中等数据范围 1e3 O(n^2) 优化至 O(n)
1856. 子数组最小乘积的最大值open in new window中等数据范围 1e5
2104. 子数组范围和open in new window中等数据范围 1e3 O(n^2) 优化至 O(n)
2281. 巫师的总力量和open in new window困难数据范围 1e5
题目难度
316. 去除重复字母open in new window中等去重、字典序最小
221021 天池-03. 整理书架open in new window中等数量不大于 limit、最小排列

区间问题

907. 子数组的最小值之和

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

public class Solution907 {
    private static final long MOD = 1000000007;

    public int sumSubarrayMins(int[] arr) {
        int n = arr.length;

        // step1: 求左侧第一个 "严格小于" arr[i] 的下标,如没有则为 -1
        Deque<Integer> stack1 = new ArrayDeque<>();
        int[] left = new int[n];
        Arrays.fill(left, -1);
        for (int i = 0; i < n; i++) {
            while (!stack1.isEmpty() && arr[i] <= arr[stack1.peek()]) {
                stack1.pop();
            }
            if (!stack1.isEmpty()) {
                left[i] = stack1.peek();
            }
            stack1.push(i);
        }

        // step2: 求右侧第一个 "小于等于" arr[i] 的下标,如没有则为 n
        Deque<Integer> stack2 = new ArrayDeque<>();
        int[] right = new int[n];
        Arrays.fill(right, n);
        for (int i = n - 1; i >= 0; i--) {
            // <= 为避免重复计算
            while (!stack2.isEmpty() && arr[i] < arr[stack2.peek()]) {
                stack2.pop();
            }
            if (!stack2.isEmpty()) {
                right[i] = stack2.peek();
            }
            stack2.push(i);
        }

        long sum = 0;
        for (int i = 0; i < n; i++) {
            long cnt = (long) (i - left[i]) * (right[i] - i) % MOD;
            sum += arr[i] * cnt % MOD;
            sum %= MOD;
        }
        return (int) sum;
    }
}

字典序最小

316. 去除重复字母

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

public class Solution316 {
    public String removeDuplicateLetters(String s) {
        // 右侧(含自身)元素频次
        int[] cntArr = new int[26];
        for (char ch : s.toCharArray()) {
            cntArr[ch - 'a']++;
        }

        // 栈中元素频次
        int[] stackArr = new int[26];
        Deque<Character> stack = new ArrayDeque<>();
        for (char ch : s.toCharArray()) {
            // 无法入栈
            if (stackArr[ch - 'a'] == 1) {
                cntArr[ch - 'a']--;
                continue;
            }
            // 栈顶元素能出栈
            while (!stack.isEmpty() && stack.peek() > ch && cntArr[stack.peek() - 'a'] > 1) {
                char pop = stack.pop();
                cntArr[pop - 'a']--;
                stackArr[pop - 'a']--;
            }
            stack.push(ch);
            stackArr[ch - 'a']++;
        }

        int sz = stack.size();
        char[] chars = new char[sz];
        for (int i = sz - 1; i >= 0; i--) {
            chars[i] = stack.pop();
        }
        return new String(chars);
    }
}

221021 天池-03. 整理书架

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;

public class Tianchi221022T3 {
    public int[] arrangeBookshelf(int[] order, int limit) {
        // 右侧(含自身)元素频次
        Map<Integer, Integer> cntMap = new HashMap<>();
        for (int x : order) {
            cntMap.put(x, cntMap.getOrDefault(x, 0) + 1);
        }
        // 栈中元素频次
        Map<Integer, Integer> stackMap = new HashMap<>();

        Deque<Integer> stack = new ArrayDeque<>();
        for (int x : order) {
            // 无法入栈
            if (stackMap.getOrDefault(x, 0) == limit) {
                cntMap.put(x, cntMap.get(x) - 1);
                continue;
            }

            // 栈顶元素能出栈
            while (!stack.isEmpty() && stack.peek() > x && cntMap.get(stack.peek()) > limit) {
                int pop = stack.pop();
                cntMap.put(pop, cntMap.get(pop) - 1);
                stackMap.put(pop, stackMap.get(pop) - 1);
            }

            stack.push(x);
            stackMap.put(x, stackMap.getOrDefault(x, 0) + 1);
        }

        // => int[]
        int sz = stack.size();
        int[] res = new int[sz];
        for (int i = sz - 1; i >= 0; i--) {
            res[i] = stack.pop();
        }
        return res;
    }
}

(全文完)