leetcode算法基础 单调队列及优先级队列

单调队列 239. 滑动窗口最大值

  题目,单调队列要实现三个操作:移出滑动窗口左边界元素时,判断该元素和队列中头元素是否相同,相同则移除;加入队列时,判断加入元素是否大于队尾元素,如果大于,移除队尾元素直到队列空或者不大于队尾元素;返回当前滑动窗口的最大值,即单调队列的对头元素。
  为了方便在滑动窗口移动时,单调队列的出队操作,可以将数组的下标存入队列,这样就可以直接判断该元素是否需要出队。

class MyDeque{

    Deque<Integer> deque = new ArrayDeque<>();

    public void poll(int val){
        if (!deque.isEmpty() && val == deque.peek()) {
            deque.pop();
        }
    }

    public void add(int val){
        while (!deque.isEmpty() && val > deque.getLast()){
            deque.removeLast();
        }
        deque.addLast(val);
    }

    public int peek(){
        return deque.peek();
    }
}

public class l_6_239 {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] re = new int[nums.length - k + 1];
        MyDeque myDeque = new MyDeque();
        int num = 0;
        for (int i = 0; i < k; i++){
            myDeque.add(nums[i]);
        }
        re[num++] = myDeque.peek();
        for (int i = k; i < nums.length; i++){
            myDeque.poll(nums[i - k]);
            myDeque.add(nums[i]);
            re[num++] = myDeque.peek();
        }
        return re;
    }

    public int[] maxSlidingWindow1(int[] nums, int k) {
        Deque<Integer> deque = new ArrayDeque<>();
        int num = 0;
        int[] re = new int[nums.length - k + 1];
        for (int i = 0; i < k; i++) {
            while (!deque.isEmpty() && nums[deque.getLast()] < nums[i]) {
                deque.removeLast();
            }
            deque.add(i);
        }
        re[num++] = nums[deque.peek()];
        for (int i = k; i <nums.length; i++){
            if (deque.peek() == i - k) {
                deque.pop();
            }
            while (!deque.isEmpty() && nums[deque.getLast()] < nums[i]) {
                deque.removeLast();
            }
            deque.add(i);
            re[num++] = nums[deque.peek()];
        }
        return re;
    }
}

优先级队列 347. 前 K 个高频元素

  题目,topk (前k大)用小顶堆,维护堆大小不超过 k 即可。每次压入堆前和堆顶元素比较,如果比堆顶元素还小,直接扔掉,否则压入堆。检查堆大小是否超过 k,如果超过,弹出堆顶。复杂度是 nlogk。避免使用大顶堆,因为你得把所有元素压入堆,复杂度是 nlogn,而且还浪费内存。java的大顶堆小顶堆是由优先级队列的compare()函数实现的,o1.getValue() - o2.getValue()是小顶堆,反过来就是大顶堆。compare函数的重写也可以利用lambda表达式

PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());

  另外这道题,还利用了hash表的遍历,这是一个新的知识点,利用Set<Map.Entry<Integer, Integer>> entries = map.entrySet(),可以获得hash表的集合。

public int[] topKFrequent(int[] nums, int k) {
    int[] result = new int[k];
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int num : nums) {
        map.put(num, map.getOrDefault(num, 0) + 1);
    }

    Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
    // 根据map的value值正序排,相当于一个小顶堆
    PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
        @Override
        public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
            return o1.getValue() - o2.getValue();
        }
    });
    for (Map.Entry<Integer, Integer> entry : entries) {
        queue.offer(entry);
        if (queue.size() > k) {
            queue.poll();
        }
    }
    for (int i = k - 1; i >= 0; i--) {
        result[i] = queue.poll().getKey();
    }
    return result;
}

  其实对于少量数据也可以用大顶堆,加入全部数据后输出前k个元素,这样时间复杂度和空间复杂度都会比小顶堆高。

public int[] topKFrequent(int[] nums, int k) {
    HashMap<Integer,Integer> map = new HashMap<>();
    for(int num : nums){
        map.put(num, map.getOrDefault(num, 0) + 1);
    }
    int[] re = new int[k];
    PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> map.get(o2) - map.get(o1));
    pq.addAll(map.keySet());
    for(int i = 0; i < k; i++){
        re[i]=pq.remove();
    }
    return re;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值