---
title: LeetCode 第 49 题「字母异位词分组」Python 解法：通过字母排序与哈希表高效实现单词分类详解
created: 2026-03-10
updated: 2026-03-10
type: summary
tags: ["anagrams", "hash", "notes", "sorting", "telegram"]
external: http://go/ui/posts/2140/
status: inbox
---

好的，我们来看 LeetCode 第 49 题「字母异位词分组」。我会用简单易懂的方式解释，并提供 Python 代码。

## 问题是什么？

给你一个字符串数组，比如 `["eat", "tea", "tan", "ate", "nat", "bat"]`。你要把「字母异位词」放在同一个组里。什么是字母异位词？就是两个单词包含的字母完全相同，只是顺序不一样。比如：
- `"eat"`、`"tea"`、`"ate"` 都是由 `a`、`e`、`t` 这三个字母组成的，所以它们是一组。
- `"tan"` 和 `"nat"` 都是由 `a`、`n`、`t` 组成的，所以是另一组。
- `"bat"` 由 `a`、`b`、`t` 组成，没有其他单词和它一样，所以自己一组。

输出结果可以是任意顺序，例如 `[["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]`。

## 怎么解决？

一个很自然的想法：如何判断两个单词是不是字母异位词？把它们按字母排序，如果排序后的字符串相同，它们就是异位词。例如：
- `"eat"` 排序后是 `"aet"`
- `"tea"` 排序后也是 `"aet"`
- `"ate"` 排序后也是 `"aet"`
- `"tan"` 排序后是 `"ant"`
- `"nat"` 排序后也是 `"ant"`
- `"bat"` 排序后是 `"abt"`

所以我们可以用一个字典（哈希表），把排序后的字符串作为「键」，把原单词加入到这个键对应的列表中。

具体步骤：
1. 创建一个空字典。
2. 遍历数组中的每个单词：
   - 对单词的字母进行排序，得到排序后的字符串 `sorted_word`。
   - 如果 `sorted_word` 不在字典中，就创建一个新的列表作为值。
   - 把当前单词加入到 `sorted_word` 对应的列表中。
3. 最后，字典中所有的值（列表）就是分组结果，把它们返回即可。

这种方法非常直观，就像把相同「签名」的单词放在同一个抽屉里。

## 代码实现（Python）

```python
class Solution:
    def groupAnagrams(self, strs: list[str]) -> list[list[str]]:
        from collections import defaultdict

        # 创建一个默认值为列表的字典
        anagram_groups = defaultdict(list)

        for s in strs:
            # 对字符串排序，得到键
            sorted_s = ''.join(sorted(s))
            # 将原字符串加入对应的组
            anagram_groups[sorted_s].append(s)

        # 返回字典中所有值组成的列表
        return list(anagram_groups.values())
```

### 解释一下关键点：
- `sorted(s)` 返回一个字符列表，比如 `sorted("eat")` 得到 `['a', 'e', 't']`。
- `''.join(...)` 把列表重新拼成字符串 `"aet"`。
- `defaultdict(list)` 是一个特殊的字典，当访问不存在的键时，会自动创建一个空列表，方便我们直接 `append`。

### 时间复杂度和空间复杂度
- 时间复杂度：O(NK log K)，其中 N 是字符串数量，K 是字符串最大长度。排序每个字符串需要 O(K log K)。
- 空间复杂度：O(NK)，用于存储结果。

如果字符串长度很大，也可以改用计数法（用字母出现次数的元组作键）来避免排序，但排序法已经足够简单，适合初中生理解。

希望这个解释对你有帮助！如果还有疑问，随时问我。
