要解决这个问题,我们需要统计每个元素的出现频率,然后找到频率最高的 kk 个元素,并按升序排列。要求算法的时间复杂度必须优于 O(nlogn)O(n \log n),因此我们可以使用 堆 或 桶排序 来优化频率统计和排序过程。
算法思路
-
统计频率
- 使用哈希表(Python 的
collections.Counter)来统计每个数字的出现频率。 - 时间复杂度:O(n)O(n)。
- 使用哈希表(Python 的
-
寻找前 kk 个高频元素
- 通过最小堆维护前 kk 个频率最高的元素。
- 时间复杂度:O(nlogk)O(n \log k)。
-
排序结果
- 将前 kk 个元素按升序排序。
- 时间复杂度:O(klogk)O(k \log k)。
-
返回结果
- 将结果转化为以逗号分隔的字符串格式。
代码实现
以下是基于最小堆的实现:
from collections import Counter
import heapq
def topKFrequent(nums, k):
# 1. 统计每个数字的出现频率
count = Counter(nums)
# 2. 使用最小堆维护前 k 个频率最高的元素
heap = []
for num, freq in count.items():
heapq.heappush(heap, (freq, num)) # 将 (频率, 元素) 入堆
if len(heap) > k:
heapq.heappop(heap) # 堆的大小保持为 k
# 3. 提取堆中的元素并按升序排列
top_k = sorted([num for freq, num in heap])
# 4. 转化为逗号分隔的字符串
return ",".join(map(str, top_k))
# 测试用例
if __name__ == "__main__":
print(topKFrequent([1, 1, 1, 2, 2, 3], 2)) # 输出: "1,2"
print(topKFrequent([1], 1)) # 输出: "1"
print(topKFrequent([4, 4, 4, 2, 2, 2, 3, 3, 1], 2)) # 输出: "2,4"
代码详解
1. 使用 Counter 统计频率
collections.Counter 是 Python 内置的哈希表工具,用于统计元素出现的次数:
count = Counter(nums)
对于输入 nums = [1, 1, 1, 2, 2, 3],得到的 count 为:
{1: 3, 2: 2, 3: 1}
2. 使用最小堆维护前 kk 个高频元素
heapq 是 Python 的优先队列工具,默认是最小堆。通过频率进行堆排序:
- 将每个元素
(频率, 值)推入堆中。 - 如果堆的大小超过 kk,弹出堆顶最小元素。
例如,对于 nums = [1, 1, 1, 2, 2, 3] 和 k = 2,堆的变化过程如下:
- 插入
(3, 1),堆为[(3, 1)] - 插入
(2, 2),堆为[(2, 2), (3, 1)] - 插入
(1, 3),堆为[(1, 3), (3, 1), (2, 2)] - 弹出最小频率,堆为
[(2, 2), (3, 1)]
最终,堆中保留的是频率前 kk 高的元素。
3. 按升序排列
将堆中的元素按值排序:
top_k = sorted([num for freq, num in heap])
对于 heap = [(2, 2), (3, 1)],提取元素并排序后得到 [1, 2]。
4. 转化为字符串
使用 ",".join(map(str, top_k)) 将结果转换为以逗号分隔的字符串。
复杂度分析
-
时间复杂度
- 统计频率:O(n)O(n)
- 堆操作:O(nlogk)O(n \log k),其中 kk 是堆的大小
- 排序:O(klogk)O(k \log k)
- 总复杂度:O(nlogk+klogk)O(n \log k + k \log k)。对于 k≪nk \ll n,时间复杂度接近 O(nlogk)O(n \log k)。
-
空间复杂度
- 频率计数表:O(u)O(u),其中 uu 是数组中不同元素的数量。
- 堆:O(k)O(k)。
- 总空间复杂度:O(u+k)O(u + k)。
测试结果
测试样例 1
nums = [1, 1, 1, 2, 2, 3]
k = 2
输出:
"1,2"
测试样例 2
nums = [1]
k = 1
输出:
"1"
测试样例 3
nums = [4, 4, 4, 2, 2, 2, 3, 3, 1]
k = 2
输出:
"2,4"
总结
通过使用哈希表统计频率和最小堆维护前 kk 个高频元素,我们成功将时间复杂度优化为 O(nlogk)O(n \log k),满足题目对效率的要求。