相似题目:

  1. 【常考排序算法】堆排序.
  2. 【剑指 Offer】 40. 最小的k个数.
  3. 【LeetCode】215. 数组中的第K个最大元素.

1. 题目描述

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

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

示例 2:

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

提示:

  1. 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
  2. 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
  3. 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。你可以按任意顺序返回答案。

2. 解题思路

  1. 借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
  2. 维护一个元素数目为 k k k 的最小堆(记住:求最小 top k 问题用最大堆,求最大 top k 问题用最小堆)
  3. 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较。如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
  4. 最终,堆中的 k个元素即为前 k 个高频元素

具体可见下图:

3. 代码

法一、纯手写

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        def heapify(k, i):
            c1 = 2 * i + 1     # 左孩子
            c2 = 2 * i + 2     # 右孩子
            min = i            # 假设最小值在 i 的位置
            if c1 < k and hashList[c1][1] < hashList[min][1]:
                min = c1
            if c2 < k and hashList[c2][1] < hashList[min][1]:
                min = c2
            if min != i:
                hashList[min], hashList[i] = hashList[i], hashList[min]  # 整对 一起调换
                heapify(k, min)

        # 将元素和出现的次数存入哈希表
        hashmap = {
   }
        for num in nums:
            if num not in hashmap:
                hashmap[num] = 1
            else:
                hashmap[num] += 1
        # 将哈希表转换为二维列表,便于按照顺序索引
        hashList = [[key, value] for key, value in hashmap.items()]
        # build heap 由于需要取部分数据建立堆,不方便对 arr[:k] 进行传参,所以采用嵌套函数,
        # 免去多次传参的麻烦
        for i in range((k-2)//2, -1, -1):
            heapify(k, i)
        # 依次和最小堆的堆顶比较,若比堆顶小,无需处理;如果比堆顶大,则和堆顶元素调换
        n = len(hashList)
        for i in range(k, n):
            if hashList[0][1] < hashList[i][1]:
                hashList[0] = hashList[i]   # 整个单元,即[key, value] 对都调换,而不是只有值调换
                heapify(k, 0)
        ans = [hashList[i][0] for i in range(k)]  # 前 k 个[key, value] 对 的 key
        return ans

结果如同:

法二、库函数
LeetCode官方题解。但是面试的时候,估计还是手写比较好。

class Solution:
    def topKFrequent(self, nums, k):
        """ :type nums: List[int] :type k: int :rtype: List[int] """ 
        count = collections.Counter(nums)   
        return heapq.nlargest(k, count.keys(), key=count.get) 

参考

  1. LeetCode题解 1.
  2. LeetCode题解 2.