zoukankan      html  css  js  c++  java
  • LeetCode347. 前 K 个高频元素(相关话题:优先队列,最小堆)

     

     

     

     题解分析(见课程8-7和8-8):首先求出所有元素的频次(映射Map),然后利用频次求出前k高的元素(优先队列)。具体来说,问题转化为“在N个元素中选出前M个元素,M<<N”,最朴素的想法是采用排序,但使用快排等高级排序算法,复杂度在NlogN;更好的方法是采用优先队列,复杂度在NlogM,其思路是使用优先队列,维护当前看到的前M个元素,不断将前M大元素中最小的元素进行替换,因此需要使用最小堆。那么最小堆如何实现呢?

    ——对最大堆底层实现进行修改,即最大堆核心逻辑比较时符号需要改变。

    ——仍然采用最大堆,不一定值越大优先级越高,自己定义元素的值越小,优先级越高即可。 

    队首的元素就是优先队列优先级最高的元素,因此,在自定义优先级下,频次最低的元素优先级最高。如果新遍历的key 的频次比当前前k高频次中频次最小的元素要搞,那么就将有限队列中队首的元素出队,然后进队一个新的元素。该算法的复杂度是NlogK。这是利用自己定义的优先队列,内部是一个最大堆。

    用Java标准库中的优先队列PriorityQueue,内部默认是一个最小堆。如果想要改变Java标准库中的类相应的比较方式,解决方案是定义一个新的类(比较器,自定义在优先队列中优先级的比较方式),它实现的是Comparator这个接口,在优先队列构造时,让这个比较器作为优先队列的一个参数,比较器定义了在优先队列中如何决定谁的优先级大。

    再进一步,不需要专门为PriorityQueue设置一个类,将一个只用一次的类的声明写成匿名类,即传的参数设为一个匿名类,然后把compare的逻辑写出来即可。

    更进一步,匿名类具有变量捕获的能力,匿名类中能拿到算法中声明的所有不可改变的变量,利用匿名类改变Java内置类型之间比较的逻辑。

    还能进一步化简,从Java8开始,匿名类可以直接使用lamda表达式。

    import java.util.LinkedList;
    import java.util.TreeMap;
    import java.util.PriorityQueue;
    import java.util.Comparator;
    
    class Solution {
        public int[] topKFrequent(int[] nums, int k) {
    
            TreeMap<Integer, Integer> map = new TreeMap<>();
            for(int num: nums){
                if(map.containsKey(num)){
                    map.put(num, map.get(num) + 1);
                }else{
                    map.put(num, 1);
                }
            }
    
            PriorityQueue<Integer> pq = new PriorityQueue<>(
                (a,b) -> map.get(a) - map.get(b)    // Java8下,匿名类直接使用lamda表达式
            );
            for(int key: map.keySet()){
                if(pq.size()<k){
                    pq.add(key);
                }else if (map.get(key) > map.get(pq.peek())){
                    pq.remove();
                    pq.add(key);
                }
            }
    
            LinkedList<Integer> res = new LinkedList<>();
            while(!pq.isEmpty()){
                res.add(pq.remove());
            }
            int[] arr= new int[res.size()];
            for(int i = 0; i<res.size(); i++){
                arr[i] = res.get(i);         // LinkedList转换为原始int数组
            }
            return arr;
        }
    }
    Solution 1
  • 相关阅读:
    18_异常机制和File类
    20个简洁的 JS 代码片段
    在 Python 中实现延迟调用
    停止 Goroutine 有几种方法?
    图解Python中深浅copy
    Python 自制简单实用的日志装饰器
    Go 里的错误得这样写才优雅~
    推荐8个炫酷的 Python 装饰器!
    两个 Django 插件( django_extensions,django_toolbar)
    一文看懂Python系列之装饰器(decorator)
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/12833729.html
Copyright © 2011-2022 走看看