zoukankan      html  css  js  c++  java
  • LeetCode——347. 前 K 个高频元素

    给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

    示例 1:

    输入: nums = [1,1,1,2,2,3], k = 2
    输出: [1,2]
    

    示例 2:

    输入: nums = [1], k = 1
    输出: [1]
    

    说明:

    • 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
    • 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

    哈希表加堆排序

    这道题给了我们一个数组,让统计前k个高频的数字,那么对于这类的统计数字的问题,首先应该考虑用 HashMap 来做,建立数字和其出现次数的映射,然后再按照出现次数进行排序。可以用堆排序来做,使用一个最大堆来按照映射次数从大到小排列,在 C++ 中使用 priority_queue 来实现,默认是最大堆,参见代码如下:

    c++

    class Solution {
    public:
        vector<int> topKFrequent(vector<int>& nums, int k) {
            unordered_map<int, int> m;
            priority_queue<pair<int, int>> q;
            vector<int> res;
            for (auto a : nums) ++m[a];
            for (auto it : m) q.push({it.second, it.first});
            for (int i = 0; i < k; ++i) {
                res.push_back(q.top().second); q.pop();
            }
            return res;
        }
    };
    

    java

    class Solution {
        public List<Integer> topKFrequent(int[] nums, int k) {
            // 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
            HashMap<Integer,Integer> map = new HashMap();
            for(int num : nums){
                if (map.containsKey(num)) {
                   map.put(num, map.get(num) + 1);
                 } else {
                    map.put(num, 1);
                 }
            }
            // 遍历map,用最小堆保存频率最大的k个元素
            PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
                @Override
                public int compare(Integer a, Integer b) {
                    return map.get(a) - map.get(b);
                }
            });
            
            for (Integer key : map.keySet()) {
                if (pq.size() < k) {
                    pq.add(key);
                } else if (map.get(key) > map.get(pq.peek())) {
                    pq.remove();
                    pq.add(key);
                }
            }
            // 取出最小堆中的元素
            List<Integer> res = new ArrayList<>();
            while (!pq.isEmpty()) {
                res.add(pq.remove());
            }
            return res;
        }
    }
    

    python

    class Solution:
        def topKFrequent(self, nums, k):
            count = collections.Counter(nums)   
            return heapq.nlargest(k, count.keys(), key=count.get) 
    

    桶排序

    这里还可以使用桶排序,在建立好数字和其出现次数的映射后,按照其出现次数将数字放到对应的位置中去,这样从桶的后面向前面遍历,最先得到的就是出现次数最多的数字,找到k个后返回即可,参见代码如下:

    c++

    class Solution {
    public:
        vector<int> topKFrequent(vector<int>& nums, int k) {
            unordered_map<int, int> m;
            vector<vector<int>> bucket(nums.size() + 1);
            vector<int> res;
            for (auto a : nums) ++m[a];
            for (auto it : m) {
                bucket[it.second].push_back(it.first);
            }
            for (int i = nums.size(); i >= 0; --i) {
                for (int j = 0; j < bucket[i].size(); ++j) {
                    res.push_back(bucket[i][j]);
                    if (res.size() == k) return res;
                }
            }
            return res;
        }
    };
    

    java

    //基于桶排序求解「前 K 个高频元素」
    class Solution {
        public List<Integer> topKFrequent(int[] nums, int k) {
            List<Integer> res = new ArrayList();
            // 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
            HashMap<Integer,Integer> map = new HashMap();
            for(int num : nums){
                if (map.containsKey(num)) {
                   map.put(num, map.get(num) + 1);
                 } else {
                    map.put(num, 1);
                 }
            }
            
            //桶排序
            //将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标
            List<Integer>[] list = new List[nums.length+1];
            for(int key : map.keySet()){
                // 获取出现的次数作为下标
                int i = map.get(key);
                if(list[i] == null){
                   list[i] = new ArrayList();
                } 
                list[i].add(key);
            }
            
            // 倒序遍历数组获取出现顺序从大到小的排列
            for(int i = list.length - 1;i >= 0 && res.size() < k;i--){
                if(list[i] == null) continue;
                res.addAll(list[i]);
            }
            return res;
        }
    }
    

    python

    class Solution:
        def topKFrequent(self, nums: List[int], k: int) -> List[int]:
            from collections import Counter
            
            c = Counter(nums)
            buckets = [[] for _ in  range(len(nums) + 1)]
            
            for x, y in c.items():
                buckets[y].append(x)
            res = [] 
            for i in range(len(nums), -1, -1):
                if len(res) > k:
                    break
                res.extend(buckets[i])
            return res[:k]
    
  • 相关阅读:
    有效的完全平方数
    除自身以外数组的乘积leetcode
    三个数的最大乘积 leetcode
    不同的二叉搜索树
    fenzhi
    leetcode二分查找之大于给定元素的最小元素744. Find Smallest Letter Greater Than Target (Easy)
    leetcode二分查找之求开方
    总结U-Net网络及他的变体
    451. Sort Characters By Frequency (Medium) 按照字符出现次数对字符串排序(leetcode排序)
    记一次 PHP调用Java Webservice
  • 原文地址:https://www.cnblogs.com/wwj99/p/12382028.html
Copyright © 2011-2022 走看看