LeetCode 777. 在 LR 字符串中交换相邻字符
题目描述

题意分析
两个等长字符串只含
L、R、X,允许把XL变成LX,或把RX变成XR,判断能否从起始串得到目标串。可以把X看作空位:L只能向左移,R只能向右移,两个棋子不能直接交换。
解法:双指针匹配非 X 字符
核心思路
[!blue]
每次操作只交换一个棋子与空位,两个棋子永远不能越过彼此。因此去掉
X后,两串的L、R序列必须完全相同,按出现次序匹配的两个字符才代表同一个棋子。设某个棋子的起点下标为
i、目标下标为j。L只能左移,所以必须i >= j;R只能右移,所以必须i <= j。相等表示不需要移动。这些方向条件与顺序条件都是必要的。它们也足够:可以先从左到右把所有
L移到目标位置。此前的L已经就位;此前的R的起点不晚于自身目标,而自身目标又在当前L的目标左侧,因此不会挡在当前移动区间中。再从右到左处理R,右侧的R已就位,L也已固定,保持的相对顺序保证这一段同样只有空位。于是所有棋子都能按允许方向到位。实现时无需模拟这些交换,用两个指针分别跳过
X,逐一检查棋子类型和位置即可。若只剩一串还有棋子,数量或顺序不一致;若两边都耗尽,所有棋子都通过了检查,返回true。
解题步骤
- 双指针跳过各自字符串中的 X。
- 若一方已结束,检查另一方是否也没有剩余棋子。
- 比较当前非 X 字符和对应位置的移动方向。
- 通过检查后同时推进,直到全部匹配。
代码实现
class Solution {
public boolean canTransform(String start, String end) {
int n = start.length();
int i = 0;
int j = 0;
while (i < n || j < n) {
while (i < n && start.charAt(i) == 'X') {
i++;
}
while (j < n && end.charAt(j) == 'X') {
j++;
}
if (i == n && j == n) {
return true;
}
if (i == n || j == n) {
return false;
}
char a = start.charAt(i);
char b = end.charAt(j);
if (a != b) {
return false;
}
// 左移棋子的目标位置不能比起点更靠右。
if (a == 'L' && i < j) {
return false;
}
// 右移棋子的目标位置不能比起点更靠左。
if (a == 'R' && i > j) {
return false;
}
i++;
j++;
}
return true;
}
}
func canTransform(start string, end string) bool {
n := len(start)
i, j := 0, 0
for i < n || j < n {
for i < n && start[i] == 'X' {
i++
}
for j < n && end[j] == 'X' {
j++
}
if i == n && j == n {
return true
}
if i == n || j == n {
return false
}
if start[i] != end[j] {
return false
}
// 左移棋子的目标位置不能比起点更靠右。
if start[i] == 'L' && i < j {
return false
}
// 右移棋子的目标位置不能比起点更靠左。
if start[i] == 'R' && i > j {
return false
}
i++
j++
}
return true
}
复杂度分析
- 时间复杂度:$O(n)$,两个指针各自只向前移动。
- 空间复杂度:$O(1)$。
关键点总结
[!green]
- 顺序约束与方向约束缺一不可。
- X 表示可移动的空位,不需要逐步模拟每次交换。
- 结束时两边必须同时耗尽非 X 字符。
易错点总结
[!yellow]
- 只比较 L、R 总数:无法发现相对顺序变化。
- 把 L 和 R 的位置不等式写反:会接受禁止方向的移动。
- 只要任一指针结束就返回 true:另一串可能还有未匹配棋子。
- 要求 X 的下标保持不变:空位本来就会随操作移动。
- 外层只在两指针都未结束时继续:可能漏查另一串末尾剩余的棋子,应确认两边同时耗尽。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 2337. 移动片段得到字符串 | 中等 | 移动规则等价:L只能左移、R只能右移,空位符号不同;可复用去除空位后的次序与位置约束判定。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!