题目来源:🔒LeetCode249:移位字符串分组
问题抽象: 给定一个字符串数组 strs,要求将字符串按 移位等价关系 分组(同一组内字符串可通过统一循环移位操作相互转换),需满足以下核心需求:
-
移位等价定义:
- 循环移位操作:字符串中所有字符 同时移动相同位数(如
'a'→'b'、'z'→'a'); - 等价判定:若存在整数
k使字符串s每个字符循环移位k位后等于t,则s和t属于同一组。
- 循环移位操作:字符串中所有字符 同时移动相同位数(如
-
输入约束:
- 数组长度
∈ [0, 100],字符串长度∈ [1, 100]; - 字符均为小写字母(
'a'-'z'); - 需处理空数组(返回空分组)。
- 数组长度
-
分组要求:
- 返回 分组列表(子列表顺序任意,组内字符串顺序任意);
- 不同组间字符串不可通过移位相互转换;
- 示例:
strs=["abc","bcd","acef","xyz","az","ba","a","z"]
→ 分组[["abc","bcd"],["acef"],["xyz"],["az","ba"],["a","z"]]。
-
关键策略:
- 归一化表示:
- 将字符串首字符移位至
'a'(如"bcd"→ 首字符'b'→'a',整体移-1位 →"abc"); - 其余字符同步移位(循环处理
z→a);
- 将字符串首字符移位至
- 哈希分组:以归一化字符串为键,将原字符串分组存储。
- 归一化表示:
-
计算约束:
- 时间复杂度 O(n·L)(
n为字符串数,L为字符串长度); - 空间复杂度 O(n·L)(存储分组结果)。
- 时间复杂度 O(n·L)(
输入:字符串数组 strs(如 ["abc","bcd"])
输出:分组列表(如 [["abc","bcd"]])。
解题思路
核心问题分析
判断两个字符串是否属于同一组,需满足:
- 长度相同:长度不同无法通过移位转换。
- 字符相对距离一致:
- 若将字符串首字符对齐至
'a',其他字符同步偏移相同距离,则所有同组字符串会映射到相同的归一化字符串。 - 例1:
"abc"→ 首字符'a'对齐至'a',其他字符偏移量0→ 归一化为"abc"。 - 例2:
"bcd"→ 首字符'b'对齐至'a'(偏移-1),则'c'→'b'、'd'→'c'→ 归一化为"abc"。 - 例3:
"az"→ 首字符'a'对齐至'a','z'偏移量25→ 归一化为"az";"ba"→ 首字符'b'对齐至'a'(偏移-1),'a'偏移后为'z'→ 归一化为"az"。
- 若将字符串首字符对齐至
算法选择
- 哈希表分组:以归一化字符串为
Key,原字符串列表为Value。 - 归一化方法:
- 计算首字符与
'a'的偏移量diff = s[0] - 'a'。 - 将字符串所有字符减去
diff(若结果< 'a',则+26保证在a~z范围内)。
- 计算首字符与
- 复杂度:
- 时间复杂度:O(n×m)(
n为字符串数量,m为平均长度)。 - 空间复杂度:O(n×m)(存储所有归一化字符串)。
- 时间复杂度:O(n×m)(
代码实现(Java版)🔥点击下载源码
class Solution {
public List<List<String>> groupStrings(String[] strings) {
// 1. 创建哈希表:Key=归一化字符串,Value=原字符串列表
Map<String, List<String>> groups = new HashMap<>();
for (String s : strings) {
// 2. 计算首字符偏移量
int diff = s.charAt(0) - 'a';
char[] normalized = s.toCharArray();
// 3. 归一化操作:所有字符减去偏移量,处理越界
for (int i = 0; i < normalized.length; i++) {
char shiftedChar = (char) (normalized[i] - diff);
if (shiftedChar < 'a') {
shiftedChar += 26; // 处理 z→a 的循环
}
normalized[i] = shiftedChar;
}
// 4. 以归一化字符串为Key,将原字符串加入对应分组
String key = new String(normalized);
groups.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
}
// 5. 返回所有分组(无需额外排序,因归一化一致性保证分组正确)
return new ArrayList<>(groups.values());
}
}
代码说明
- 归一化处理:
- 首字符对齐
'a'后,后续字符同步偏移,确保同组字符串映射到相同Key。 - 字符偏移后若
< 'a'(如'a' - 1 → 'z'),通过+26修正。
- 首字符对齐
- 哈希表操作:
- 使用
computeIfAbsent简化分组列表的初始化。
- 使用
- 边界处理:
- 单字符字符串(如
"a")归一化后仍为"a",自动归入同一组。
- 单字符字符串(如
- 效率优化:
- 直接操作字符数组,避免
String拼接开销。 - 一次遍历完成分组,无冗余操作。
- 直接操作字符数组,避免


被折叠的 条评论
为什么被折叠?



