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

40 阅读2分钟

问题描述:

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

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

思路解析:

解决方案步骤

  1. 统计频率

    使用 collections.Counter 来统计数组 nums 中每个元素的出现频率。

    这一步的时间复杂度是 O(n),其中 n 是数组 nums 的长度。

  2. 构建小顶堆

    使用 Python 的 heapq 模块来构建一个大小为 k 的小顶堆。

    堆中的元素是包含元素值和频率的元组,但堆是根据频率来排序的(频率作为元组的第一个元素)。

    遍历频率统计结果,对于每个元素和它的频率:

    a. 如果堆的大小小于 k,直接将元素(频率,数值)添加到堆中。

    b. 如果堆的大小等于 k,并且当前元素的频率大于堆顶元素的频率,则弹出堆顶元素,并将当前元素添加到堆中。

    这一步的时间复杂度是 O(nlogk),因为每次插入和删除操作的时间复杂度是 O(logk),并且我们最多对 n 个元素执行这些操作。

  3. 提取堆中元素

    从堆中提取所有元素,只保留数值部分。

    这一步的时间复杂度是 O(k),因为我只是遍历堆中的 k 个元素。

  4. 排序

    对提取出的数值进行排序,以满足题目要求的按数值升序排列。

    这一步的时间复杂度是 O(klogk),因为排序算法(如快速排序、归并排序或堆排序)的时间复杂度通常是 O(mlogm),其中 m 是要排序的元素数量,在这里 m=k。

  5. 构建结果字符串

    将排序后的数值转换为字符串,并用逗号分隔。

    这一步的时间复杂度是 O(k),因为字符串连接和格式化操作的时间复杂度与元素数量成线性关系。

代码实现:

from collections import Counter
def solution(nums, k):
    p = Counter(nums)
    most_elements = p.most_common(k)
    sort_elements = sorted([num for num, count in most_elements])
    result = ','.join(map(str, sort_elements))
    return result

个人思考:

  • 虽然排序步骤的时间复杂度是 O(klogk),但在大多数情况下,由于 k≪n(即 k 远小于 n),整个算法的总时间复杂度仍然优于 O(nlogn)。
  • 如果 k 的值非常大,以至于排序步骤成为性能瓶颈,那么可能需要考虑使用其他数据结构或算法来优化这一步,比如使用平衡二叉搜索树(如 AVL 树或红黑树)来同时维护频率和数值的排序。然而,这些数据结构在插入和删除操作上的时间复杂度通常也是 O(logm),并且在实现上可能更加复杂。