字母异位词分组
题目
给你一个字符串数组,将字母异位词组合在一起。字母异位词是由重新排列源单词的字母得到的新单词,源单词中的每个字母通常恰好使用一次。
示例
输入:strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:[["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]
分组内部的顺序不限,分组的顺序也不限。
思路
先观察一组异位词:eat、tea、ate。它们包含的字母完全相同(e、a、t),只是排列顺序不同。
如果把每个单词的字母按字典序排好,这三个单词会得到同一个结果:aet。也就是说,排序后的字符串可以唯一标识一组异位词。两个单词互为异位词,当且仅当它们排序后的结果相等。
基于这一点,做法分三步:
- 准备一个哈希表:键为排序后的字符串,值为该组单词的列表。
- 遍历每个单词:将字母排序得到键,把原单词加入对应的分组。
- 遍历完成后,哈希表中的每个值就是一个分组,全部收集起来返回。
1 | class Solution { |
复杂度分析
设单词个数为 n,最长单词长度为 k。
- 时间复杂度:每个单词排序耗时 O(klog k),整体为 O(nklog k)。
- 空间复杂度:哈希表存放全部单词,为 O(nk)。
进阶:用字母计数代替排序
当字符集固定(例如只含小写字母)时,可以用每个字母的出现次数作为分组依据,省去排序:
- 统计单词中 26 个字母各出现几次,把计数结果编码成一个字符串作为键。
- 每个单词的统计耗时 O(k),整体为 O(nk),在单词较长时优于排序法。
- C++ 中可以用
array<int, 26>完成统计,再把计数拼成字符串。
判断两个字符串是否互为异位词,有两种等价方式:排序后相等,或者字母计数相同。按数据规模和个人习惯选择即可。
两个词互为异位词,等价于:26 个字母各自出现的次数完全相同。排列顺序不影响计数。
eat拆成字母:e a t,
统计:a 1 次,e 1 次,t 1 次;
tea拆成字母:t e a,
统计:a 1 次,e 1 次,t 1 次。
顺序不同,但统计结果一样,所以它们分到同一组。这就是计数法的依据。
| 单词 | 各字母出现次数(非零部分) | 计数 key | 归属组 |
|---|---|---|---|
| eat | a1 | e1 | t1 |
| tea | a1 | e1 | t1 |
| ate | a1 | e1 | t1 |
| tan | a1 | n1 | t1 |
| nat | a1 | n1 | t1 |
| bat | a1 | b1 | t1 |
1 | class Solution { |
小结
这类”按特征分组”的问题,通用做法是:先找出一个能代表等价类的特征(这里选取排序结果),再用哈希表把特征相同的元素聚拢。用空间换取时间,
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 山川不念旧!
评论




