单调栈数据结构学习之旅

189 阅读1分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」。

一、单调栈是什么?

单调栈(MonotonousStack)一种特别设计的栈结构,为了解决如下的问题:

给定一个可能含有重复值的数组arr,i位置的数一定存在如下两个信息:

  1. arr[i]的左侧离i最近并且小于或者大于arr[i]的数在哪?
  2. arr[i]的右侧里i最近并且小于或者大于arr[i]的数在哪?

二、单调栈能做什么?

如果想得到arr中所有位置的两个信息,怎么能让得到信息的过程尽量快。那么到底怎么设计呢?

image.png

数组中没有重复的数的设计方案

public static int[][] getNearLessNoRepeat(int[] arr) {
    if (arr == null || arr.length == 0) {
        return null;
    }
    int N = arr.length;
    int[][] ans = new int[N][2];
    // 只存位置!
    Stack<Integer> stack = new Stack<>();
    // 遍历到i位置的数arr[i]
    for (int i = 0; i < N; i++) {
        // 当前位置的数比栈顶位置的数小,没有机会往上摞,则弹出栈顶
        while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
            int j = stack.pop();
            int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
            ans[j][0] = leftLessIndex;
            ans[j][1] = i;
        }
        stack.push(i);
    }
    while (!stack.isEmpty()) {
        int j = stack.pop();
        int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
        ans[j][0] = leftLessIndex;
        ans[j][1] = -1;
    }
    return ans;
}

数组中存在重复的数的设计方案

栈 + 链表(相同值存在一起)

public static int[][] getNearLess(int[] arr) {
    if (arr == null || arr.length == 0) {
        return null;
    }
    int N = arr.length;
    int[][] ans = new int[N][2];
    Stack<List<Integer>> stack = new Stack<>();
    for (int i = 0; i < N; i++) {
        while (!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]) {
            List<Integer> popIds = stack.pop();
            int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
            for (Integer popId : popIds) {
                ans[popId][0] = leftLessIndex;
                ans[popId][1] = i;
            }
        }
        if (!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]) {
            stack.peek().add(i);
        } else {
            List<Integer> list = new ArrayList<>();
            list.add(i);
            stack.push(list);
        }
    }
    while (!stack.isEmpty()) {
        List<Integer> popIds = stack.pop();
        int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
        for (Integer popId : popIds) {
            ans[popId][0] = leftLessIndex;
            ans[popId][1] = -1;
        }
    }
    return ans;
}

三、友情链接

滑动窗口数据结构学习之旅