LeetCode 249. 移位字符串分组
题目描述
题意分析
对一个小写字母字符串,每次可以把所有字符同时向后移动一位,超过
z就循环回a。将能够经过若干次这种整体移动而互相得到的字符串分到同一组。移位要求所有位置使用同一个偏移量,不能分别改变各字符,也不能交换字符顺序。字符串长度与位置关系都要保留,分组中保存原字符串,重复输入也按各次出现保留。
解法:相对首字符归一化后分组
核心思路
[!blue]
整体移位会改变每个字符的绝对字母值,但不会改变它相对于首字符的循环距离。把每一位减去首字符,再对
26取模,就得到不受整体平移影响的关系。用这个关系生成统一签名:把首字符映射成
a,第i位映射成'a' + (s[i] - s[0] + 26) % 26。签名与原串等长,首位固定为a,其他位置保存相对偏移,因此长度和原有顺序都不会丢失。两个字符串若能整体移位互相得到,所有位置和首字符增加的是同一偏移,相减后签名必然一致。反过来,若两串签名一致,选择把第一串首字符移到第二串首字符的那个统一偏移,其他各位置也会同时对齐,所以签名相同足以保证属于同组。
哈希表以签名为键,以原字符串列表为值。逐串生成签名并追加到对应组,最后收集所有列表。单字符只有自身相对自身的零偏移,因此自然可以归入同一类;签名只用于分类,不替换结果里的原文。
解题步骤
- 创建签名到字符串列表的哈希表。
- 对每个字符串,逐位置计算相对首字符的模
26偏移,再编码为a..z的签名字符。- 用完整签名找到或创建分组,将原字符串追加进去。
- 处理全部输入后,返回哈希表中的所有分组。
代码实现
class Solution {
public List<List<String>> groupStrings(String[] strings) {
Map<String, List<String>> groups = new HashMap<>();
for (String s : strings) {
char[] key = new char[s.length()];
for (int i = 0; i < s.length(); i++) {
key[i] = (char) ('a' + (s.charAt(i) - s.charAt(0) + 26) % 26);
}
groups.computeIfAbsent(new String(key), k -> new ArrayList<>()).add(s);
}
return new ArrayList<>(groups.values());
}
}
func groupStrings(strings []string) [][]string {
groups := map[string][]string{}
for _, s := range strings {
key := make([]byte, len(s))
for i := range key {
key[i] = byte('a' + (int(s[i])-int(s[0])+26)%26)
}
k := string(key)
groups[k] = append(groups[k], s)
}
out := make([][]string, 0, len(groups))
for _, group := range groups {
out = append(out, group)
}
return out
}
复杂度分析
设字符串数量为
N,总字符数为C。
- 时间复杂度:期望 $O(N+C)$,每个字符只参与一次签名生成,字符串键的哈希也按字符处理。
- 空间复杂度:$O(N+C)$,保存各组签名和全部输入项的字符串引用,不复制原字符串内容。
关键点总结
[!green]
- 相对首字符的循环距离是整体移位的不变量,按位置保存它们就能完整标识类别。
- 签名相同与可以互相整体移位双向等价,既不会拆散同组,也不会误合并不同组。
- 长度由签名长度保留,顺序由签名位置保留,不能用字符频次或排序替代。
易错点总结
[!yellow]
- 差值可能为负,应先加
26再取模,才能把所有循环距离统一到0..25。- Go 应先把字节转换为
int再计算有符号差值,与归一化公式保持一致。- 对每个字符分别选择不同的偏移,会扩大允许变换的范围,题目只允许统一位移。
- 把字符串先排序会丢失位置关系,求成另一种分组问题。
- 将签名放进结果而不是原字符串,会改写用户要求保留的输入内容。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 49. 字母异位词分组 | 中等 | 同样用规范签名分组,但异位词忽略顺序,本题保留顺序并允许整体循环移位。 |
| 205. 同构字符串 | 简单 | 同样比较字符关系;同构允许任意一一映射,整体移位只允许统一的模 26 偏移。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!