青训营X豆包MarsCode技术训练营伴学笔记(4)|查找热点数据问题|豆包MarsCode AI刷题

102 阅读5分钟

一、题目解析

1. 问题描述

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

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

输入:

  • nums: 一个正整数数组
  • k: 一个整数

返回:

返回一个包含 k 个元素的字符串,数字元素之间用逗号分隔。数字元素按升序排列,表示出现频率最高的 k 个元素。

参数限制:

  • 1 <= nums[i] <= 10^4
  • 1 <= nums.length <= 10^5
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

测试样例

样例1:

输入:nums = [1, 1, 1, 2, 2, 3], k = 2
输出:"1,2"
解释:元素 1 出现了 3 次,元素 2 出现了 2 次,元素 3 出现了 1 次。因此前两个高频元素是 1 和 2。

样例2:

输入:nums = [1], k = 1
输出:"1"

样例3:

输入:nums = [4, 4, 4, 2, 2, 2, 3, 3, 1], k = 2
输出:"2,4"

2. 题目解析

这道题的目的是找到一个整数数组 nums 中出现频率前 k 高的元素,并按升序返回这些元素,以逗号分隔。题目明确了时间复杂度要求优于 O(nlogn)O(nlog⁡n),这意味着我们需要高效的算法来处理可能包含大量元素的数组。

思路:

统计频率:首先使用哈希表(或 Python 的 Counter)统计每个元素在数组中的出现次数,这一步可以在 O(n)O(n)O(n) 时间内完成。

使用堆找出前 K 个高频元素:由于我们只需找出前 k 个高频元素,使用大小为 k 的最小堆可以有效控制复杂度。heapq.nlargest 函数可以在 O(nlog⁡k)O(n \log k)O(nlogk) 的时间内获得频率最高的 k 个元素。

按升序排序并返回结果:堆的结果按频率从高到低排列,最后一步将这些元素按数值升序排序。

图解:

假设 nums = [1, 1, 1, 2, 2, 3]k = 2

  • Step 1: 统计频率。得到 {1: 3, 2: 2, 3: 1}
  • Step 2: 将频率前 k 高的元素放入最小堆,堆中元素是 [1, 2]
  • Step 3: 排序输出。最终结果为 "1,2"

3. 代码详解

def solution(nums, k):
    # 1. 统计每个元素的频率
    count = Counter(nums)  # O(n)
    
    # 2. 使用最小堆找出前 k 个高频元素,按频率排序后按数值升序排列
    top_k = [item for item, _ in heapq.nlargest(k, count.items(), key=lambda x: x[1])]
    
    # 3. 按数值升序排序并返回格式化后的字符串
    top_k_sorted = sorted(map(str, top_k))  # 按升序排序
    return ','.join(top_k_sorted)

4. 时间和空间复杂度分析

  • 时间复杂度

    • 统计频率的时间复杂度是 O(n)O(n)
    • heapq.nlargest 的复杂度是 O(nlogk)O(nlog⁡k)
    • 排序堆中 k 个元素的复杂度是 O(klogk)O(klog⁡k)
    • 总体时间复杂度为 O(nlogk+klogk)O(nlog⁡k+klog⁡k)
  • 空间复杂度

    • Counter 使用 O(n)O(n) 的空间来存储每个元素的频率。
    • 堆使用 O(k)O(k) 的空间。
    • 总体空间复杂度为 O(n+k)O(n+k)

二、知识总结

新知识点:

  1. 哈希表(Counter :用于统计频率。Counter 是字典的子类,常用于统计各元素的出现次数,便于频率分析。
  2. 最小堆(heapq :通过维护一个大小为 k 的最小堆,可以在 O(nlogk)O(nlog⁡k) 时间复杂度内找到频率最高的 k 个元素。这比直接排序整个数组要高效得多。
  3. 字符串拼接与排序:题目要求返回按数值升序排列的字符串格式,这一步虽然不是算法的核心,却有助于提高题目完成度和代码的可读性。

个人理解与学习建议:

对于入门同学来说,熟悉哈希表的基本用法和堆的操作是解题的关键。通过练习可以巩固这些数据结构的概念,并且逐渐提升解题效率。可以从简单的频率统计和堆的使用题目入手,如“数组中出现次数最多的元素”等题目,循序渐进地掌握这些概念。

三、学习计划

  1. 制定刷题计划:先梳理数据结构和算法基础知识,逐步增加难度。建议从基础的哈希表和排序算法开始,再逐渐引入堆和优先队列相关题目。
  2. 错题反思:将刷题过程中遇到的错题记录下来,进行总结分析,反复练习。特别是对时间复杂度有要求的题目,要通过错题找到高效的解决方法。
  3. 分解题目:对复杂题目进行分步分解,确保每一步都理解清楚。比如,在本题中,理解堆的引入原因和频率统计的思路,是解题的关键。

四、工具运用

在学习和刷题过程中,可以结合 AI 工具与其他资源,如 豆包MarsCode AI等平台:

  1. AI 辅助理解:在遇到复杂的算法时,可以通过 AI 获取详细的解析或代码优化建议。
  2. 题目推荐:通过 AI 提供的题目推荐功能,有针对性地寻找和练习相关题目,从而更高效地掌握特定的数据结构和算法。
  3. 结合社区资源:AI 能够帮助查询特定题解和优化策略,再结合讨论区中其他用户的解题思路,可以加深对题目和算法的理解。
  4. 制定个性化学习计划:根据自身情况,利用 AI 为自己定制刷题计划,并持续调整计划,帮助实现学习目标。