132模式[TreeMap的特点和用法 & 单调栈实践]

268 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,132模式[TreeMap的特点和用法 & 单调栈实践] - 掘金 (juejin.cn)

前言

TreeMap不同于优先队列,TreeMap删除元素O(logn),而且能寻找target值,或者它的floor/ceiling,TreeMap以Key进行排序。对于单调栈的使用很简单,但是要将问题转换到这上面来,还需要多多练习才能信手拈来。

一、132模式

image.png

二、枚举1 和 枚举 3

1、枚举3 & 将数组分开 & treemap的寻找速度

// 132模式
public class Find132pattern {
    /*
    自己的思考记录:
    target:寻找132子序列,即寻找波峰,存在返回true
    仅仅单减必不可能出现波峰,单增时记住最大值即可,一旦右边找到比起小的就true
    先找单增,再单减。
    review:
    有bug,没这么简单,因为要求第3个不仅要小于第2个,还要大于第一个。
    这种题,我的思考度&见识度都不够多。
    思路重新分析:枚举三个,纯纯的暴力,2*10^5^,O(n2)都已经超时了,必须往O(nlogn/n)上靠。
    本题是一个3元组,如果固定前后,在左侧右侧暴力,肯定超时。
    但是固定中间就将数组分为了两组,左边用变量记录最小,右边用TreeMap来做,就可以达到O(logn)
     */
    public boolean find132pattern(int[] nums) {
        int n = nums.length;
        if (n < 3) return false;

        TreeMap<Integer, Integer> right = new TreeMap<>();

        // 将后边的元素加入map,并分组。
        for (int i = nums.length - 1; i > 1; i--) right.put(nums[i], right.getOrDefault(nums[i], 0) + 1);

        int min = nums[0];//左侧最小元素。
        for (int i = 1; i < nums.length - 1; i++) {
            Integer key = right.ceilingKey(min + 1);
            if (key != null && key < nums[i]) return true;

            right.put(nums[i + 1], right.get(nums[i + 1]) - 1);
            if (right.get(nums[i + 1]) == 0) right.remove(nums[i + 1]);

            min = Math.min(min, nums[i]);
        }
        return false;
        // review : TreeMap:1-针对key排序;2-可直接firstKey()取最值;3-可ceilingKey/floorKey(int)寻找元素。
        // 总结:这种几元组,可往枚举不同的位方向思考。分析几位的大小等关系特性。
    }
}

2、枚举1 & 单调栈得到当前3和最到2

// 单调栈解法
class Find132pattern2 {
    // 可从后往前枚举1,用单调栈拿到当前的3和最大的2
    public boolean find132pattern(int[] nums) {
        int n = nums.length;
        if(n < 3) return false;

        Deque<Integer> que = new LinkedList<>();

        que.push(nums[n - 1]);
        int second = Integer.MIN_VALUE;// 记录已经得到右边最大的2.
        // 从后往前遍历,方便2/3的获取。
        for(int i = n - 2;i >= 0;i--){
            // 此时2 < 3,要是1 < 2,则1 < 3,满足条件。
            if(second > nums[i]) return true;
            // 既然nums[i]不能作为1,就把它作为2/3.
            while(!que.isEmpty() && nums[i] > que.peek()) second = que.poll();//记录最大的2
            // 当nums[i]比已经选出来的值还小就没必要加入进去了,毕竟考虑出栈的都是较大的2.
            if(nums[i] > second) que.push(nums[i]);
        }
        return false;
    }
}

总结

1)对于这种三元组问题,应该去固定一些值,找到规律,使用合适的数据结构将时间复杂度降下来。

2)TreeMap:1-针对key排序;2-可直接firstKey()取最值;3-可ceilingKey/floorKey(int)寻找元素。

参考文献

[1] LeetCode 132模式