题目解析 查找热点数据问题 | 豆包MarsCode AI刷题

109 阅读3分钟

查找热点数据问题

题目链接

问题描述

给你一个整数数组 nums 和一个整数 k,请你用一个字符串返回其中出现频率前 k 高的元素。请按升序排列。

你所设计算法的时间复杂度必须优于 O(n log n),其中 n 是数组大小。

输入

  • nums: 一个正整数数组
  • k: 一个整数

返回

返回一个包含 k 个元素的字符串,数字元素之间用逗号分隔。数字元素按升序排列,表示出现频率最高的 k 个元素。

参数限制

  • 1 <= nums[i] <= 10^4
  • 1 <= nums.length <= 10^5
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

测试样例

样例1:

输入:nums = [1, 1, 1, 2, 2, 3], k = 2
输出:"1,2"
解释:元素 1 出现了 3 次,元素 2 出现了 2 次,元素 3 出现了 1 次。因此前两个高频元素是 1 和 2。

样例2:

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

样例3:

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

解决思路

  1. 频率统计:首先,需要统计数组中每个元素出现的次数。我们可以使用 collections.Counter 来实现这个功能,它可以在 O(n) 的时间复杂度内计算频率,其中 n 是数组的大小。
  2. 堆排序:为了找出频率前 k 高的元素,使用堆(特别是最小堆)是一个非常合适的选择。通过 heapq.nlargest 函数,我们可以高效地获取前 k 个频率最大的元素。heapq.nlargest 的时间复杂度是 O(n log k),这比 O(n log n) 更优。
  3. 升序排序:获取到前 k 个元素后,我们需要按升序对这些元素进行排序。由于 k 的值相对较小,排序的时间复杂度为 O(k log k),这通常是可以接受的。
  4. 结果输出:将最终的元素按要求的格式拼接成字符串,元素之间用逗号分隔。

代码实现

import collections
import heapq

def solution(nums, k):
    count = collections.Counter(nums)
    top_k = heapq.nlargest(k, count.keys(), key=lambda x: (count[x], -x))  # 获取前k个频率最大的元素
    top_k.sort()  # 升序排序
    return ",".join(map(str, top_k))  # 结果转换为字符串格式

if __name__ == "__main__":
    print(solution([1, 1, 1, 2, 2, 3], 2) == "1,2")
    print(solution([1], 1) == "1")
    print(solution([4, 4, 4, 2, 2, 2, 3, 3, 1], 2) == "2,4")

代码解释

  1. collections.Counter(nums) :用来统计数组 nums 中每个元素的频率,返回一个字典,键是元素,值是出现的次数。
  2. heapq.nlargest(k, count.keys(), key=lambda x: (count[x], -x)) :这个函数用来获取出现频率前 k 高的元素。count.keys() 提供了所有不同的元素,key=lambda x: (count[x], -x) 用来按照频率排序,如果频率相同,则按元素的值降序排列,确保结果的稳定性。
  3. top_k.sort() :对前 k 个高频元素按升序进行排序,以满足题目要求。
  4. ",".join(map(str, top_k)) :将排序后的元素列表转为字符串,并以逗号分隔。

复杂度分析:

  • 时间复杂度

    • 统计频率:O(n),其中 n 是数组的长度。
    • 使用 heapq.nlargest 获取前 k 个元素:O(n log k)。
    • 排序前 k 个元素:O(k log k)。
    • 总时间复杂度:O(n log k),比 O(n log n) 更优。
  • 空间复杂度:O(n),主要用于存储频率计数。

总结

  • 思路:通过频率统计和堆排序实现高效的查找前 k 个高频元素。
  • 复杂度分析:时间复杂度为 O(n log k),空间复杂度为 O(n)。
  • 优化:相比传统的 O(n log n) 排序方法,O(n log k) 的方法能够显著减少计算量,特别是当 k 比 n 小的时候。