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
  • 相关阅读:
    Vue- 对象语法 v-bind:class与对象语法的使用(重要)
    关于vue中$emit事件问题
    深入理解vue.js2.0指令v-for使用及索引获取
    到底vuex是什么?
    Vue.js学习系列二 —— vuex学习实践笔记(附DEMO)
    前端HTML5几种存储方式的总结
    JSON和JS对象之间的互转
    Vue2.0子父组件通信
    C#字符串和16进制转换
    C#中int32 的有效值范围
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/12833729.html
Copyright © 2011-2022 走看看