LeetCode | 字母异位词分组

968 字
5 分钟
LeetCode | 字母异位词分组

分类:哈希表 / 字符串 / 排序 / 计数

题目#

给定一个字符串数组 strs,把所有字母异位词分到同一组。

字母异位词指的是:两个字符串包含的字母完全相同,只是顺序不同。

示例:

输入:strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:[["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]

返回结果中,每一组内部的顺序、组和组之间的顺序都不重要。

讲解#

这道题的关键是:同一组字母异位词需要有同一个标识。

排序法#

把字符串里的字符sort排序后,字母异位词会得到同一个结果。所以可以把排序后的字符串作为哈希表的 key。

具体做法:

  1. 准备一个字典 mp
  2. 遍历每个字符串 st
  3. st 里的字符排序,得到 key
  4. 把原字符串 st 放进 mp[key] 对应的列表里。

计数法#

字母异位词不一定要排序才能判断,也可以数每个字母出现了几次。

所以可以用一个长度为 26 的数组记录每个小写字母出现次数。这个数组转成元组后,也可以作为哈希表的 key。

计数法避免了排序,所以每个字符串只需要扫描一遍。

复杂度#

这里 n 是字符串数量,k 是单个字符串的最大长度。

  • 排序法:
    • 时间复杂度:O(n * k * log(k))
    • 空间复杂度:O(n * k)
  • 计数法:
    • 时间复杂度:O(n * k)
    • 空间复杂度:O(n * k)

排序法里的 log(k) 来自排序。对一个长度为 k 的字符串排序,常见排序算法的时间复杂度是 O(k * log(k))

可以用“归并排序”来理解这个复杂度。假设有 k 个字符要排序:

第 1 层:把 k 个字符分成 2 组
第 2 层:继续分成 4 组
第 3 层:继续分成 8 组
...

每往下一层,问题规模大约减半,所以总层数大约是 log(k)

分完以后还要一层一层合并。每一层合并时,所有字符加起来都会被处理一遍,也就是 k 次左右。

所以可以理解成:

每一层处理 k 个字符
一共有 log(k) 层
总时间复杂度 = O(k * log(k))

Python 的 sorted 底层不是简单的归并排序,而是 Timsort。不过从这道题分析复杂度时,可以按常见排序的 O(k * log(k)) 来理解。

计数法不排序,只扫描每个字符串里的字符。扫描一个长度为 k 的字符串是 O(k),扫描 n 个字符串就是 O(n * k)

一些语法基础#

sorted(st) 会把字符串 st 里的字符拿出来排序,返回的是列表,不是字符串。sorted(“eat”)结果是:[“a”, “e”, “t”]

join 是字符串的方法,格式是:连接符.join(字符串列表),例如”-“.join([“a”, “e”, “t”])结果是:“a-e-t”

计数法里会用到 ord(ch) - ord("a")ord(ch) 会得到字符对应的数字编号,所以减去 ord("a") 之后,就能把小写字母转成 025 的下标:

tuple(counts) 是把列表转成元组。字典的 key 必须是不可变的,列表可以修改,所以不能当 key;元组不能修改,所以可以当 key。计数法里要把 counts 转成 tuple 再放进字典。

代码#

排序法#

源码#

from collections import defaultdict
from typing import List
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
mp = defaultdict(list)
for st in strs:
key = "".join(sorted(st))
mp[key].append(st)
return list(mp.values())

计数法#

源码#

from collections import defaultdict
from typing import List
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
mp = defaultdict(list)
for st in strs:
counts = [0] * 26
for ch in st:
counts[ord(ch) - ord("a")] += 1
mp[tuple(counts)].append(st)
return list(mp.values())

测试#

def normalize(groups):
return sorted(sorted(group) for group in groups)
sol = Solution()
ans = sol.groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])
assert normalize(ans) == normalize([["bat"], ["nat", "tan"], ["ate", "eat", "tea"]])
assert normalize(sol.groupAnagrams([""])) == normalize([[""]])
assert normalize(sol.groupAnagrams(["a"])) == normalize([["a"]])
print("PASS")

参考资料#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

LeetCode | 字母异位词分组
https://leetcode.cn/problems/group-anagrams/
作者
平昊阳
发布于
2026-08-01
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
平昊阳
乘长风,破巨浪, 展鸿图于未央!
--
总访问量
--
访客数
公告
欢迎来到我的个人博客!欢迎关注交流吖!
更多相关公告,见
社交-留言」。
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
站点统计
文章
66
分类
16
标签
93
总字数
477,284
运行时长
0
最后活动
0 天前

文章目录