问题描述
给你一个整数数组 nums 和一个整数 k,请你用一个字符串返回其中出现频率前 k 高的元素。请按升序排列。 要求所设计算法的时间复杂度必须优于 O(n log n),其中 n 是数组大小。
分析思路
- 统计频率:首先,我们需要统计数组中每个元素的出现频率。这一步可以使用 Python 的
collections.Counter类来实现,它能够以字典的形式返回每个元素及其对应的频率。 - 维护最小堆:为了找到频率前
k高的元素,我们可以使用一个最小堆(最小优先队列)。在 Python 中,heapq模块提供了对堆的支持。我们将元素及其频率作为元组加入堆中,如果堆的大小超过k,则弹出堆顶元素(即最小频率的元素)。这样,堆中始终维护着频率最高的k个元素。 - 提取结果:从堆中取出前
k个高频元素,并按升序排列。 - 时间复杂度分析:统计频率的时间复杂度为 O(n),维护最小堆的时间复杂度为 O(n log k),因为每次插入和删除操作的时间复杂度都是 O(log k),最多进行 n 次。因此,总的时间复杂度为 O(n log k),满足题目要求。
代码实现
python代码
from collections import Counter
import heapq
def solution(nums, k):
# 统计每个元素的频率
frequency = Counter(nums)
# 使用最小堆来维护前 k 个高频元素
min_heap = []
for num, freq in frequency.items():
# 将元素和频率加入堆中
heapq.heappush(min_heap, (freq, num))
# 如果堆的大小超过 k,弹出堆顶元素(最小频率的元素)
if len(min_heap) > k:
heapq.heappop(min_heap)
# 从堆中取出前 k 个高频元素
result = [num for _, num in min_heap]
# 按升序排列
result.sort()
return result
代码详解
frequency = Counter(nums)这行代码使用 Counter 来统计每个元素的出现频率。
min_heap = [] for num, freq in frequency.items(): heapq.heappush(min_heap, (freq, num)) if len(min_heap) > k: heapq.heappop(min_heap)这里我们使用最小堆来维护前 k 个高频元素。每次插入元素时,如果堆的大小超过 k,我们就弹出堆顶元素(即频率最小的元素)。
result = [num for _, num in min_heap] result.sort()最后,我们从堆中取出前 k 个元素,并按升序排列。
知识总结
堆排序是一种基于比较的排序算法,利用堆这种数据结构来进行排序。堆是一种近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。
堆分为两种类型:
- 最大堆(Max Heap) :在这种堆中,每个父节点的值都大于或等于其所有子节点的值,因此堆的根节点是整个堆中的最大值。
- 最小堆(Min Heap) :在这种堆中,每个父节点的值都小于或等于其所有子节点的值,因此堆的根节点是整个堆中的最小值。
堆排序算法通常使用最大堆来进行升序排序,或者使用最小堆来进行降序排序。以下是堆排序的详细步骤:
建堆(Heapify)
-
初始化堆:将输入数据组织成最大堆或最小堆的形式。通常是从最后一个非叶子节点开始向上调整,直到整个数组满足堆的性质。
-
调整堆:对于每个非叶子节点,执行以下操作:
- 比较当前节点与其子节点,如果不符合最大堆或最小堆的性质,则交换当前节点与子节点中最大或最小的那个,然后继续向下比较和交换,直到满足堆的性质。
排序
- 堆顶与最后一个元素交换:将堆顶元素(最大或最小值)与数组的最后一个元素交换,此时最后一个元素即为最大或最小值。
- 调整堆:交换后,除了最后一个元素外,其余元素再次调整为最大堆或最小堆。
- 重复交换和调整:重复上述步骤,每次都将堆顶元素与当前堆的最后一个元素交换,并调整剩余的堆,直到所有元素都被移除堆,此时数组即为有序。
总结
通过运用智能刷题工具——豆包MarsCode AI,我在解题速度、知识点梳理和错误题目剖析方面取得了显著的进步。展望未来,我将继续整合AI的先进功能与经典学习资源,一方面巩固和深化基础知识,另一方面挑战更高难度的题目,以实现学习能力的全面提升。