首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【算法】堆、优先级队列

【算法】堆、优先级队列

作者头像
三三是该溜子
发布2025-01-25 20:02:51
发布2025-01-25 20:02:51
2740
举报
文章被收录于专栏:该溜子的专栏该溜子的专栏

零:堆、优先级队列算法技巧

1:创建优先级队列的方法

PriorityQueue<> heap = new PriorityQueue<>((a,b) -> a-b); 小根堆 差为负数,小的a放前面

PriorityQueue<> heap = new PriorityQueue<>((a,b) -> b-a); 大根堆

2:添加元素

offer()和add()都可以

在容量有限的 PriorityQueue 中,offer() 更安全,因为它会在队列已满时返回 false,而 add() 会抛出 IllegalStateException 异常。

3:弹出元素

.poll()

4:获取堆顶元素

.peek()

5:Collections.reverse()

逆序一个集合中的元素,返回类型为List

6:堆的大小

.size();

一:前k个高频单词

心得感悟:————大根堆不要纠结,就记住一个小根堆就行了,大根堆反过来就OK

1:用Pair类型巧妙的将咱们map数据结构和堆联系到了一起

2:此题提升了写堆的比较规则,在lambda表达式中,巧妙的运用compareTo()方法:使用方式——b.compareTo(a) b<a 返回负数 。

3:b.compareTo(a) b<a 返回负数 结合 (a,b)->{ (b.compareTo(a) } 花括号中是负数,创建的是大根堆 这个式子等价于 (a,b)-> (b-a)

4:为什么if条件中用的是equals()方法,而不是==,因为Integer是int的包装类型,是一个对象,==比较的是对象的引用地址值,equals()才能比较对象中属性的值

5:如果使用idea,没有内置Pair类,我们需要自己实现一个Pair

代码语言:javascript
复制
class Pair<K,V>{
    private K key;
    private V value;
    public Pair(K key , V value){
        this.key = key;
        this.value = value;
    }
    public K getKey(){
        return key;
    }
    public V getValue(){
        return value;
    }
}
代码语言:javascript
复制
class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        //我的两个问题——1:怎么把map中的元素按照重写的比较规则放入到堆里面
        //2:因为map中是键值对结构,但是堆只能放一个类型,怎么放是一个问题

        //第一步:把所有字符串放入map中,map结构去重
        Map<String,Integer> map = new HashMap<>();
        for(String str : words){
            map.put(str,map.getOrDefault(str,0)+1);
        }

        //第二步:new 一个堆  重写比较规则
        PriorityQueue<Pair<String,Integer>> heap = new PriorityQueue<>(
            (a,b)->{
                //如果出现频次相同,按字母顺序返回,创建大根堆,可以理解成首字母更小的往堆的更深处放
                if(a.getValue().equals(b.getValue())){
                    return (b.getKey().compareTo(a.getKey()));//对啊,compareTo方法怎么放啊
                }
                //依据频次创建小根堆
                return (a.getValue()-b.getValue());
            }
        );

        //第三步:遍历map,把元素放到堆里面
        for(Map.Entry<String,Integer> entry : map.entrySet()){
            heap.offer(new Pair<>(entry.getKey(),entry.getValue()));
            if(heap.size() > k){
                heap.poll();
            }
        }
        

        //第四步:让堆不断弹出元素,注意逆序(不逆序就倒着填入数组),这里采用集合的方式
        List<String> list = new ArrayList<>();
        for(int i = 0 ; i < k ; i++){
            String s = heap.peek().getKey();
            list.add(s);
            heap.poll();
        }
        Collections.reverse(list);
        return list;
    }
}

二:最后一块石头的重量

1046. 最后一块石头的重量

代码语言:javascript
复制
class Solution {
    public int lastStoneWeight(int[] stones) {
        //大根堆
        PriorityQueue<Integer> heap = new PriorityQueue<>((a,b) -> b-a);
        for(int x : stones){
            heap.add(x);
        }
        while(heap.size() >= 2){
            int a = heap.poll();
            int b = heap.poll();
            if(a != b){
                heap.add(a - b);//先弹出的大
            }
        }
        return heap.isEmpty() ? 0 : heap.peek();
    
    }
}

三:数据流中的第k大元素

心得:

1:这道题可以体会全局成员变量的好处

2:老实说这个题目读完题,给我一种无从下手的感觉,写完代码后豁然开朗,不难

代码语言:javascript
复制
class KthLargest {
    //创建全局成员变量
    private PriorityQueue<Integer> heap;//默认为小根堆
    private int _k;//堆的大小

    public KthLargest(int k, int[] nums) {
        heap = new PriorityQueue<>((a,b) -> a-b);
        _k = k;
        for(int i = 0 ; i < nums.length ; i++){
            heap.offer(nums[i]);
            if(heap.size() > _k){
                heap.poll();
            }
        }
    }
    
    public int add(int val) {
        heap.offer(val);
        if(heap.size() > _k){
            heap.poll();
        }
        return heap.peek();
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

四:数据流的中位数

295. 数据流的中位数

心得:

1:用大小根堆来处理数据流的中位数问题,算是开拓思路了

2:暴力解法就是用每次add一个元素之后就Arrays.sort();一下

代码语言:javascript
复制
class MedianFinder {
    private PriorityQueue<Integer> left;//左边是大根堆,右边是小根堆
    private 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()){
            if(left.isEmpty() || num <= left.peek()){
                left.offer(num);
            }else if(num > left.peek()){
                right.offer(num);
                left.offer(right.poll());
            }
        }else if(left.size() - right.size() == 1){
            if(num <= left.peek()){
                left.offer(num);
                right.offer(left.poll());
            }else if(num > left.peek()){
                right.offer(num);
            }
        }        
    }
    
    public double findMedian() {
        if(left.size() == right.size()){
            double ret = ( left.peek() + right.peek() ) / 2.0;
            return ret;
        }else{
            return left.peek();
        }
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 零:堆、优先级队列算法技巧
  • 一:前k个高频单词
  • 二:最后一块石头的重量
  • 三:数据流中的第k大元素
  • 四:数据流的中位数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档