【Leetcode 692.前K个高频单词】(Python3完整代码)

一、题目描述

给一非空的单词列表,返回前 k 个出现频率最高的单词。

要求:

  1. 频率高的单词排在前面;
  2. 若多个单词频率相同,按字典序升序排列;
  3. 保证答案唯一,且 1 ≤ k ≤ 单词列表中不同单词的数量

示例 1:

输入:words = ["i","love","leetcode","i","love","coding"], k = 2

输出:["i","love"]

解释:"i" 和 "love" 分别出现 2 次,"i" 字典序小于 "love",故排在前。

示例 2:

输入:words = ["the","day","is","sunny","the","the","the","sunny","is","is"], k = 4

输出:["the","is","sunny","day"]

解释:频率排序:the (4) > is (3) > sunny (2) > day (1),
           频率相同无冲突,按顺序返回前 4 个。

二、解法思路:

解法一:哈希表 + 自定义排序

1.思路分析:

  1. 统计频率:用哈希表统计每个单词的出现次数;
  2. 自定义排序:对哈希表的键值对排序,排序规则为:
    1. 优先按频率降序(频率高的在前);
    2. 频率相同时按单词字典序升序(字典序小的在前);
  3. 截取结果:取排序后前 k 个单词作为答案。

2. 完整代码(带详细注释)

class Solution: def topKFrequent(self, words: List[str], k: int) -> List[str]: # 统计每个单词的出现频率 dictword = {} for word in words: # get方法简化计数:存在则取当前值+1,不存在则默认0+1 dictword[word] = dictword.get(word, 0) + 1 # 自定义排序: # key=lambda x: (-x[1], x[0]) # -x[1]:按频率降序(负号实现降序);x[0]:频率相同时按单词字典序升序 dictword_sorted = sorted(dictword.items(), key=lambda x: (-x[1], x[0])) # 3. 截取前k个单词,组装结果列表 res = [] for key, val in dictword_sorted[:k]: res.append(key) return res

3. 代码核心解析

(1)频率统计
        words = ["i","love","leetcode","i","love","coding"]

        遍历后 dictword = {"i":2, "love":2, "leetcode":1, "coding":1}。

(2)自定义排序

sorted(dictword.items(), key=lambda x: (-x[1], x[0]))
    dictword.items():将字典转为元组列表 [("i",2), ("love",2), ("leetcode",1), ("coding",1)];

    key=lambda x: (-x[1], x[0])
            -x[1]:对频率(x [1])取负,实现降序(2 > 1);
            x[0]:频率相同时,按单词(x [0])的字典序升序("i" < "love");

    排序结果:[("i",2), ("love",2), ("coding",1), ("leetcode",1)]。
    (3)截取结果

    取前 k=2 个元组的单词部分,得到 ["i","love"],符合题目要求。

    4. 复杂度分析

    • 时间复杂度:O(nlogn)
      • 统计频率:O(n)(n 为单词列表长度);
      • 排序:O(mlogm)(m 为不同单词的数量,m≤n),是时间瓶颈;
    • 空间复杂度:O(n)
      • 哈希表存储所有不同单词,排序需额外存储元组列表,整体为O(n)。

    5. 优缺点

    • 优点:代码极简、逻辑直观,无需自定义类或掌握堆的复杂用法,新手极易上手;

    缺点:排序需遍历所有不同单词,当 n 极大(如

    10^{6}

    )且 k 极小时(如 k=10),效率低于堆解法。

    解法二:哈希表 + 小顶堆

    1. 思路分析

    针对排序解法的效率问题,用小顶堆优化:仅维护 k 个元素,避免对所有单词排序,核心逻辑:

    1. 哈希表统计频率(同解法一);
    2. 遍历哈希表,将(单词,频率)推入小顶堆,保持堆大小不超过 k
      (超过则弹出 “最小” 元素);
    3. 堆中剩余的 k 个元素是前 k 高频单词,反转后得到最终结果

    2. 完整代码(带详细注释)

    import heapq class Solution: def topKFrequent(self, words: List[str], k: int) -> List[str]: # 统计每个单词的出现频率 mapping = {} for word in words: mapping[word] = mapping.get(word, 0) + 1 # 初始化小顶堆,筛选前k个高频单词 heap = [] for key, val in mapping.items(): # 将自定义Node推入堆,heapq会按__lt__规则排序 heapq.heappush(heap, Node(key, val)) # 保持堆大小为k,超过则弹出“最小”的元素(频率最低/同频率字典序大) if len(heap) > k: heapq.heappop(heap) # 提取堆中元素并调整顺序 res = [] # 弹出堆顶(此时堆内元素是“小→大”,如[love, i]) while len(heap) > 0: temp = heapq.heappop(heap) res.append(temp.key) # 反转后得到“大→小”的正确顺序(如[i, love]) res.reverse() return res # 自定义堆节点类,实现比较逻辑 class Node: def __init__(self, key, val): self.key = key # 单词 self.value = val # 出现频率 # 核心:自定义小于(__lt__)规则,适配小顶堆的排序逻辑 def __lt__(self, other): # 规则1:频率相同 → 字典序大的单词“更小”(优先被弹出) if self.value == other.value: return self.key > other.key # 规则2:频率不同 → 频率小的单词“更小”(优先被弹出) else: return self.value < other.value

    3. 核心解析(关键难点)

    (1)自定义 Node 类的比较规则

            Python 的heapq默认是小顶堆,需重写__lt__方法(less than)适配题目规则:

    def __lt__(self, other): return self.key>other.key if self.value==other.value else self.value<other.value
    频率相同:字典序大的单词(如 "love")被判定为 “更小”,优先弹出;频率不同:频率小的单词(如 "coding")被判定为 “更小”,优先弹出。
    (2)堆筛选过程(以示例 1 为例)
    • 推入 ("i",2) → 堆:[Node (i,2)](大小 1 ≤2);
    • 推入 ("love",2) → 堆:[Node (love,2), Node (i,2)](大小 2 ≤2);
    • 推入 ("leetcode",1) → 堆大小 3>2 → 弹出堆顶(Node (leetcode,1));
    • 推入 ("coding",1) → 堆大小 3>2 → 弹出堆顶(Node (coding,1));
    • 最终堆内元素:[Node(love,2), Node(i,2)],弹出后反转得到["i","love"]。

    4. 复杂度分析

    • 时间复杂度:O(nlogk)
      • 统计频率:O(n);
      • 堆操作:每次 push/pop 为O(logk),最多执行m次(m≤n),整体为O(mlogk);
      • 当k≪n时,O(nlogk)≪O(nlogn),效率优势明显;
    • 空间复杂度:O(n)(哈希表 + 堆,堆仅占O(k))。

    5. 优缺点

    • 优点:时间效率更高,适合大数据量、小 k 的场景;
    • 缺点:代码稍复杂,需理解堆的特性和自定义比较规则。

    Read more

    《算法题讲解指南:优选算法-位运算》--35.两个整数之和,36.只出现一次的数字 ||,37.消失的两个数字

    《算法题讲解指南:优选算法-位运算》--35.两个整数之和,36.只出现一次的数字 ||,37.消失的两个数字

    🔥小叶-duck:个人主页 ❄️个人专栏:《Data-Structure-Learning》 《C++入门到进阶&自我学习过程记录》《算法题讲解指南》--从优选到贪心 ✨未择之路,不须回头 已择之路,纵是荆棘遍野,亦作花海遨游 目录 35.两个整数之和 题目链接: 题目描述: 题目示例: 解法(位运算): 算法思路: C++算法代码: 算法总结及流程解析: 36.只出现一次的数字 || 题目链接: 题目描述: 题目示例: 解法(比特位计数): 算法思路: C++算法代码: 算法总结及流程解析: 38. 消失的两个数字 题目链接: 题目描述: 题目示例: 解法(位运算): 算法思路: C++算法代码: 算法总结及流程解析: 结束语

    By Ne0inhk
    21届智能车雁过留痕备战指南|龙邱科技STC+神眼摄像头处理 高效搜线算法思路分享

    21届智能车雁过留痕备战指南|龙邱科技STC+神眼摄像头处理 高效搜线算法思路分享

    今年STC单片机首次增设摄像头组别,相信不少备战的同学想要知道这颗新U是否能够快速上手并能够像传统摄像头组别一样,高效完成图像处理,提高车模控制系统上限。 其中最突出的痛点的是:有同学搭建完核心算法组合后,可能感觉到略微卡顿或系统延迟,影响车模调试上限,我们第一次搭建完经过测试单帧处理耗时高达20多ms,这导致车辆运行稳定性和反应速度受限、甚至可能有冲出赛道的情况发生,导致调试陷入瓶颈,提速困难,短时间内难以找到有效突破方向。 针对这一高频痛点,我们结合备战同学的实际调试场景,经过反复测试、迭代优化,整理出一套实用性极强的帧率优化思路,实测验证有效,优化后单帧处理耗时可稳定降至9-11ms,彻底解决卡顿难题,这里将图像处理和以西优化思路分享给大家,希望能够帮助到更多的同学! 实测数据对比,直观呈现优化效果 图像处理方案单帧采集+处理耗时未优化(采集+处理)20ms-25ms(能感觉到慢,上限较低)优化后(采集+处理)9ms-11ms(流畅稳定,提高了上限) 同学们遇到的卡顿问题,核心症结主要集中在两点:一是内存资源不足,二是算法计算耗时过长。在拆解具体优化方法前,我

    By Ne0inhk
    Flutter 三方库 async_extension 的鸿蒙化适配指南 - 实现具备高级异步编排算法与流操作扩展的并发工具集、支持端侧复杂业务流的函数式处理实战

    Flutter 三方库 async_extension 的鸿蒙化适配指南 - 实现具备高级异步编排算法与流操作扩展的并发工具集、支持端侧复杂业务流的函数式处理实战

    欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 async_extension 的鸿蒙化适配指南 - 实现具备高级异步编排算法与流操作扩展的并发工具集、支持端侧复杂业务流的函数式处理实战 前言 在进行 Flutter for OpenHarmony 的大规模异步业务系统(如实时行情刷新、多源数据聚合)开发时,如何更优雅地处理 Future 的超时竞争、Stream 的防抖(Debounce)或复杂的并发队列控制?虽然 Dart async 包提供了基础功能,但 async_extension 进一步扩展了异步编程的边界,提供了更符合函数式范式的工具。本文将探讨如何在鸿蒙端构建极致、高效的异步处理链路。 一、原直观解析 / 概念介绍 1.1 基础原理 该库通过对 Dart 核心异步类的非侵入式扩展(Extensions)

    By Ne0inhk
    如何通过配置 HDFS 调整块大小?在什么情况下需要修改块大小?

    如何通过配置 HDFS 调整块大小?在什么情况下需要修改块大小?

    如何通过配置 HDFS 调整块大小?在什么情况下需要修改块大小? * ⚙️ 如何调整HDFS块大小 * 1. 修改配置文件(全局生效,推荐) * 2. 通过命令行临时设置(针对特定操作) * 🤔 何时需要修改块大小?——不同场景下的配置建议 * ✅ **建议增大块大小的场景** * ⚠️ **需要谨慎或考虑减小块大小的场景** * ❌ **小文件问题:不要依赖调小块来解决** * 💡 验证配置与注意事项 🌺The Begin🌺点点关注,收藏不迷路🌺 在 HDFS 中,调整块大小是一项常见的优化操作。修改块大小主要通过修改配置文件或使用特定命令参数两种方式实现。同时,选择多大的块需要根据具体的业务场景来决定,并不是越大越好或越小越好。 ⚙️ 如何调整HDFS块大小 你可以通过以下两种方式来调整HDFS的块大小: 1. 修改配置文件(全局生效,推荐) 这是最常用的方法,通过修改Hadoop的配置文件hdfs-site.xml来设置默认的块大小,该设置将对集群后续新写入的所有文件生效。 操作步骤: 1. 找到并

    By Ne0inhk