LeetCode-day2:字母异位词分组分析

博客:从「字母异位词分组」中学到的 Python 哈希与字符串处理核心技巧

题号:LeetCode #49 Group Anagrams

语言:Python

核心收获:如何设计"键(key)"来分组数据 + 深入理解 sorteddefaultdictordtuple 等关键工具


一、题目回顾

给定一个字符串数组 strs,将所有字母异位词(Anagram)组合在一起。

  • 字母异位词 :由相同字母以不同顺序组成的单词(如 "eat""tea""ate"
  • 要求:返回一个列表,每个子列表包含一组异位词

示例:

python 复制代码
输入: ["eat","tea","tan","ate","nat","bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

二、解题核心思想:用"标准化签名"作为分组依据

要判断两个字符串是否是异位词,关键是看它们包含的字母种类和数量是否完全一致

于是我们引入一个核心策略:

为每个字符串生成一个唯一的"签名(signature)",只要签名相同,就是异位词。

然后用哈希表(字典) 把相同签名的字符串归为一组。

接下来,我通过这道题学会了三种生成签名的方法,每一种都带来了新的 Python 技巧。


三、方法一:排序法 ------ 学会 ''.join(sorted(s))

✅ 核心代码:

python 复制代码
key = ''.join(sorted(s))

🔍 我学到的关键点:

  1. sorted(s) 对字符串排序后返回的是字符列表

    python 复制代码
    sorted("bac")  # → ['a', 'b', 'c'](不是 "abc"!)

    因为 sorted() 函数对任何可迭代对象操作后统一返回 list,这是 Python 的设计规范。

  2. 要用 ''.join(...) 把字符列表拼回字符串

    python 复制代码
    ''.join(['a','b','c'])  # → "abc"

    这是字符串拼接的高效方式 (比 + 快得多)。

  3. 这个字符串可作为字典的 key

    因为字符串是不可变类型,天然可哈希。

💡 应用场景:

  • 所有需要"忽略顺序、只看组成"的问题(如异位词、变位数等)

四、方法二:使用 defaultdict ------ 告别手动初始化!

✅ 核心代码:

python 复制代码
from collections import defaultdict
groups = defaultdict(list)
groups[key].append(s)  # 即使 key 不存在,也会自动创建空列表!

🔍 我学到的关键点:

  1. 传统写法很啰嗦

    python 复制代码
    if key not in groups:
        groups[key] = []
    groups[key].append(s)
  2. defaultdict(list) 自动处理"第一次出现"的情况

    • 当访问一个不存在的 key 时,它会自动调用 list() 创建一个空列表
    • 然后你可以直接 .append(),无需判断
  3. defaultdictdict 的子类,用法几乎一样

    最后仍可通过 list(groups.values()) 获取结果

💡 扩展知识:

  • defaultdict(int):用于计数(自动初始化为 0)
  • defaultdict(set):用于去重集合
  • 这是 LeetCode 分组类题目的标准模板

五、方法三:字符频次法 ------ 学会 ordtuple 作 key

✅ 核心代码:

python 复制代码
count = [0] * 26  # 初始化长度为 26 的全零列表
for char in s:
    count[ord(char) - ord('a')] += 1
key = tuple(count)  # 转为元组才能当 dict 的 key

🔍 我学到的关键点:

1. [0] * 26 快速创建固定长度列表
  • 这是初始化计数数组的惯用写法
  • for i in range(26): count.append(0) 更简洁高效
2. ord() 函数获取字符的 ASCII 码
  • ord('a') → 97

  • ord('b') → 98

  • 所以 ord(char) - ord('a') 可将小写字母映射到 0~25

    python 复制代码
    'a' → 0, 'b' → 1, ..., 'z' → 25
3. 为什么不用 if 判断?------ 数组下标天然支持"分类"
  • 以前我总想:"如果遇到 'a' 就加到 a 的计数,遇到 'b' 就加到 b......"
  • 但其实不需要 if !直接用 count[index] += 1 即可
  • 这是用空间换逻辑简化的经典思想
4. tuple(count) 让列表变成可哈希的 key
  • 字典的 key 必须是不可变类型

  • list 是可变的 → 不能当 key

  • tuple 是不可变的 → 可以当 key

    python 复制代码
    d = {}
    d[[1,2]] = 1   # ❌ 报错
    d[(1,2)] = 1   # ✅ 成功

💡 优势 vs 排序法:

  • 时间复杂度更低:O(M) vs O(M log M)(M 是字符串长度)
  • 但仅适用于小写字母等有限字符集

六、完整代码对比

✅ 方法一:排序法(推荐,简洁通用)

python 复制代码
from collections import defaultdict
from typing import List

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        groups = defaultdict(list)
        for s in strs:
            key = ''.join(sorted(s))
            groups[key].append(s)
        return list(groups.values())

✅ 方法三:频次法(高效,适合面试展示深度)

python 复制代码
from collections import defaultdict
from typing import List

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        groups = defaultdict(list)
        for s in strs:
            count = [0] * 26
            for char in s:
                count[ord(char) - ord('a')] += 1
            groups[tuple(count)].append(s)
        return list(groups.values())

七、本题带给我的核心认知升级

以前的我 现在的我
想手写排序或用一堆 if 判断字符 知道用 sorted + joinord + 数组计数
手动检查 key 是否存在再初始化 defaultdict 自动处理
不知道 list 不能当 dict 的 key 理解"可哈希"概念,会用 tuple 转换
对字符串操作不熟 掌握 sorted(s) 返回列表、''.join() 拼接

八、延伸思考

  1. 如果字符串包含大写字母、数字、符号怎么办?

    • 排序法依然适用 ✅
    • 频次法需扩展数组大小或改用 dict 计数
  2. 能否不用哈希表?

    • 可以,但时间复杂度会退化到 O(N²M),不实用
相关推荐
tod11342 分钟前
从零手写一个面试级 C++ vector:内存模型、拷贝语义与扩容策略全解析
c++·面试·职场和发展·stl·vector
囊中之锥.43 分钟前
机器学习算法详解:DBSCAN 聚类原理、实现流程与优缺点分析
算法·机器学习·聚类
AlenTech1 小时前
152. 乘积最大子数组 - 力扣(LeetCode)
算法·leetcode·职场和发展
Piar1231sdafa1 小时前
基于yolo13-C3k2-RVB的洗手步骤识别与检测系统实现_1
人工智能·算法·目标跟踪
a程序小傲1 小时前
中国邮政Java面试被问:Netty的FastThreadLocal优化原理
java·服务器·开发语言·面试·职场和发展·github·哈希算法
做科研的周师兄1 小时前
【MATLAB 实战】|多波段栅格数据提取部分波段均值——批量处理(NoData 修正 + 地理信息保真)_后附完整代码
前端·算法·机器学习·matlab·均值算法·分类·数据挖掘
天赐学c语言1 小时前
1.18 - 滑动窗口最大值 && 子类的指针转换为父类的指针,指针的值是否会改变
数据结构·c++·算法·leecode
甄心爱学习2 小时前
KMP算法(小白理解)
开发语言·python·算法
wen__xvn2 小时前
牛客周赛 Round 127
算法
大锦终2 小时前
dfs解决FloodFill 算法
c++·算法·深度优先