这道题的目的是从给定的数组 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, 2, 2, 3],k = 2 - 频率统计:
{1: 3, 2: 2, 3: 1} - 高频元素是
1和2,按升序排列返回1,2。
- 输入:
-
第二个测试用例:
- 输入:
[1],k = 1 - 频率统计:
{1: 1} - 只有一个元素
1,返回1。
- 输入:
-
第三个测试用例:
- 输入:
[4, 4, 4, 2, 2, 2, 3, 3, 1],k = 2 - 频率统计:
{4: 3, 2: 3, 3: 2, 1: 1} - 高频元素是
4和2,按升序排列返回2,4。
- 输入:
时间复杂度分析
- 统计频率:
Counter(nums)的时间复杂度是O(n),其中n是数组nums的长度。 - 构建堆:对于每一个不同的元素,
heapq.heappush()操作的时间复杂度是O(log k),因此总共的堆操作时间复杂度是O(n log k),因为在最坏情况下,n个不同的元素可能都被插入堆中。 - 排序:排序堆中的
k个元素的时间复杂度是O(k log k)。由于k最多是数组中不同元素的个数,排序操作的复杂度相对较小。 - 最终复杂度:总体的时间复杂度是
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 时。