刷题打卡:查找热点数据问题| 豆包MarsCode AI刷题

100 阅读4分钟

这道题的目的是从给定的数组 nums 中找出出现频率最高的 k 个元素,并按升序返回。分析代码:

导入模块

pythonCopy Code
import heapq
from collections import Counter
  • heapq 是 Python 标准库中的一个模块,提供了堆排序(heap queue)的实现。它支持最小堆和最大堆等操作。这里我们使用最小堆来处理频率最高的元素。
  • collections.Counter 是一个很方便的工具,它用于统计可迭代对象中元素的频率,返回一个字典样式的对象,其中键是元素,值是该元素的频率。

函数定义

pythonCopy Code
def solution(nums, k):
  • nums 是输入的整数数组。
  • k 是需要返回的出现频率最高的 k 个元素。

统计频率

pythonCopy Code
count = Counter(nums)
  • 这行代码使用 Counter(nums) 来统计数组 nums 中每个元素的出现次数。Counter 返回一个字典,其中键是元素,值是该元素在 nums 中出现的频率。

初始化堆

pythonCopy Code
heap = []
  • 初始化一个空的堆,用来存储频率和对应的元素。

构建堆

pythonCopy Code
for num, freq in count.items():
    heapq.heappush(heap, (freq, num))
    if len(heap) > k:
        heapq.heappop(heap)
  • for num, freq in count.items() 遍历 count 中的每一个元素及其频率。
  • heapq.heappush(heap, (freq, num)) 将元组 (freq, num) 插入到堆中,堆是基于频率排序的,频率较小的元素会被推到堆顶。
  • if len(heap) > k: 当堆中的元素数量超过 k 时,使用 heapq.heappop(heap) 弹出堆顶元素。这个操作保证堆中始终只保留出现频率最高的 k 个元素。堆中保持的是一个 k 大小的最小堆,其中堆顶元素对应的是当前频率最小的元素。

排序和返回结果

pythonCopy Code
result = sorted([num for _, num in heap])
  • 这里从堆中提取出所有的 num(即元素),并按升序排序。因为题目要求返回的是升序排列的 k 个最频繁的元素,所以排序操作是必要的。
pythonCopy Code
return ",".join(map(str, result))
  • ",".join(map(str, result)) 将排序后的 result 列表转换为字符串,每个元素之间用逗号分隔,最终返回这个字符串。

测试用例分析

pythonCopy Code
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. 第一个测试用例

    • 输入:[1, 1, 1, 2, 2, 3]k = 2
    • 频率统计:{1: 3, 2: 2, 3: 1}
    • 高频元素是 1 和 2,按升序排列返回 1,2
  2. 第二个测试用例

    • 输入:[1]k = 1
    • 频率统计:{1: 1}
    • 只有一个元素 1,返回 1
  3. 第三个测试用例

    • 输入:[4, 4, 4, 2, 2, 2, 3, 3, 1]k = 2
    • 频率统计:{4: 3, 2: 3, 3: 2, 1: 1}
    • 高频元素是 4 和 2,按升序排列返回 2,4

时间复杂度分析

  1. 统计频率Counter(nums) 的时间复杂度是 O(n),其中 n 是数组 nums 的长度。
  2. 构建堆:对于每一个不同的元素,heapq.heappush() 操作的时间复杂度是 O(log k),因此总共的堆操作时间复杂度是 O(n log k),因为在最坏情况下,n 个不同的元素可能都被插入堆中。
  3. 排序:排序堆中的 k 个元素的时间复杂度是 O(k log k)。由于 k 最多是数组中不同元素的个数,排序操作的复杂度相对较小。
  4. 最终复杂度:总体的时间复杂度是 O(n log k + k log k)。当 k 比较小(比如 k <= n),O(n log k) 是主导项,所以算法的时间复杂度可以视为 O(n log k)

空间复杂度分析

  • count 字典需要存储数组中所有不同元素的频率,空间复杂度为 O(n)
  • heap 存储最多 k 个元素,空间复杂度为 O(k)
  • 最终空间复杂度是 O(n + k),其中 n 是数组的长度,k 是需要返回的元素个数。

总结

这个解决方案通过利用堆(优先队列)高效地找出了数组中频率最高的 k 个元素,并对结果进行了排序,最终返回按升序排列的字符串。它的时间复杂度是 O(n log k + k log k),在实际使用中通常能够满足大多数需求,特别是在 k 远小于 n 时。