【专项刷题】— 优先级队列(堆)

1、最后一块石头的重量 - 力扣(LeetCode)

思路:

  1. 使用大根堆,把数据存入大根堆中
  2. 每次取出最大的两个,进行比较
  3. 相等的话就不重新入堆,不相等的话将差值重新入堆
  4. 代码:
    public int lastStoneWeight(int[] stones) {
            //创建一个大根堆
            PriorityQueue<Integer> heap = new PriorityQueue<>((a,b) -> b - a);
            //将元素都入堆
            for(int x : stones){
                heap.offer(x);
            }
            //判断
            while(heap.size() > 1){
                int a = heap.poll();
                int b = heap.poll();
                if(a > b){
                    heap.offer(a - b);
                }
            }
            return heap.isEmpty() ? 0 : heap.peek();
        }

 2、数据流中的第 K 大元素 - 力扣(LeetCode)

思路:

  1. 使用小根堆,,让数组的值入堆
  2. 判断堆的大小,大于的话就弹出堆顶,
  3. 代码:
    class KthLargest {
    
        PriorityQueue<Integer> heap;
        int _k;
    
        public KthLargest(int k, int[] nums) {
            _k = k;
            heap = new PriorityQueue<>();
            for(int x : nums){
                heap.offer(x);
                if(heap.size() > _k){
                    heap.poll();
                }
            }
    
        }
        
        public int add(int val) {
            heap.offer(val);
            if(heap.size() > _k){
                heap.poll();
            }
            return heap.peek();
        }
    }
    

 3、前K个高频单词 - 力扣(LeetCode)

思路:利用堆来解决 TopK问题

  1. 用一个哈希表统计一下每一个单词出现的频次
  2. 创建一个大小为k的堆
    比较频次用:小根堆
    比较字典序用:大根堆
  3. 让元素依次进堆,如果堆的长度大于k的话,就弹出堆顶元素,再进堆,最后堆里面就是第k大的元素
  4. 最后提取结果,将数组逆序
  5. 代码:
    public List<String> topKFrequent(String[] words, int k) {
            //1、统计每一个单词出现的频次
            Map<String,Integer> hash = new HashMap<>();
            for(String s : words)
            {
                hash.put(s, hash.getOrDefault(s,0)+1);
            }
            //2、创建一个大小为k的堆
            PriorityQueue<Pair<String,Integer>> heap = new PriorityQueue<>
            (
                (a,b) ->
                {
                    //频次相同的话,字典序按照大根堆的方式排列
                    if(a.getValue().equals(b.getValue()))
                    {
                        return b.getKey().compareTo(a.getKey());
                    }
                    return a.getValue() - b.getValue();
                }
            );
            //3、Topk的主逻辑
            for(Map.Entry<String,Integer> e : hash.entrySet())
            {
                heap.offer(new Pair<>(e.getKey(), e.getValue()));
                if(heap.size() > k)
                {
                    heap.poll();
                }
            }
            //4、提取结果
            List<String> ret = new ArrayList<>();
            while(!heap.isEmpty())
            {
                ret.add(heap.poll().getKey());
            }
            //逆序数组
            Collections.reverse(ret);
            return ret;
        }

 4、 数据流的中位数 - 力扣(LeetCode)

思路:

  1. 解法一:每次添加一个数就重新排序,找出中位数
    解法二:使用插入排序
    解法三:创建大小堆来维护中间值(本题解法)
  2. 分两种情况:
  3. 代码:
    class MedianFinder {
    
        PriorityQueue<Integer> left;
        PriorityQueue<Integer> right;
    
        public MedianFinder() {
            //大根堆
            left = new PriorityQueue<>((a,b) -> b - a);
            //小根堆
            right = new PriorityQueue<>((a,b) -> a - b);
        }
        
        public void addNum(int num) {
            //当数量一样时
            if(left.size() == right.size()){
                //left 堆为空或者 num小于left中最大值,直接入堆
                if(left.isEmpty() || num <= left.peek()){
                    left.offer(num);
                }else{
                    //大于left中最大值的话就入right,再将right中的最小值入left,维持m >= n
                    right.offer(num);
                    left.offer(right.poll());
                }
            }else{
                //数量不一样时,看num的大小分情况讨论
                if(num <= left.peek()){
                    left.offer(num);
                    right.offer(left.poll());
                }else{
                    right.offer(num);
                }
            }
               
        }
        
        public double findMedian() {
            if(left.size() == right.size()){
                return (left.peek() + right.peek())/2.0;
            }else{
                return left.peek();
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值