持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
题目
在一个由 'L' , 'R' 和 'X' 三个字符组成的字符串(例如"RXXLRXRXL")中进行移动操作。一次移动操作指用一个"LX"替换一个"XL",或者用一个"XR"替换一个"RX"。现给定起始字符串start和结束字符串end,请编写代码,当且仅当存在一系列移动操作使得start可以转换成end时, 返回True。
示例 :
输入: start = "RXXLRXRXL", end = "XRLXXRRLX"
输出: True
解释:
我们可以通过以下几步将start转换成end:
RXXLRXRXL ->
XRXLRXRXL ->
XRLXRXRXL ->
XRLXXRRXL ->
XRLXXRRLX
提示:
1 <= len(start) = len(end) <= 10000。start和end中的字符串仅限于'L','R'和'X'。
思考
本题难度中等。
首先是读懂题意。 题目中给出了在一个由 'L' , 'R' 和 'X' 三个字符组成的字符串,我们的一次移动操作可以用一个"LX"替换一个"XL",或者用一个"XR"替换一个"RX"。判断当存在一系列移动操作使得start可以转换成end时, 返回true。否则返回false。
需要注意的是,我们可以将'XL'替换成'LX',将'RX'替换成'XR',不能反过来操作!比如经过多次移动操作,我们可以实现:
-
'XXXL' -> 'LXXX'
-
'RXXX' -> 'XXXR'
-
'RXXXL' -> 'XXRLX'
我们首先判断两个字符串的长度是否相等,不相等则一定无法通过移动操作实现转换。
接着,我们定义两个指针 i 和 j,分别指向两个字符串的索引。遍历两个字符串,跳过'X',直至字符不为'X',这样就找到了字符'L'或'R'的索引。此时,需要满足:
-
start[i] === end[j]
-
(start[i] === "L" && i >= j) || (start[i] === "R" && i <= j)
若满足,继续遍历字符串。当其中一个字符串遍历到了末尾,那么另一个字符串的其余字符只能都是'X'。若条件满足,返回true。若以上条件有一不满足,则返回false。
解答
方法一:双指针
/**
* @param {string} start
* @param {string} end
* @return {boolean}
*/
var canTransform = function (start, end) {
if (start.length !== end.length) {
return false
}
const n = start.length
let i = 0, j = 0
while (i < n && j < n) {
// 跳过'X',找到'L'或'R'的索引
while (i < n && start[i] === "X") {
i++
}
while (j < n && end[j] === "X") {
j++
}
// 此时,需要满足:
// start[i] === end[j]
// (start[i] === "L" && i >= j) || (start[i] === "R" && i <= j)
if (i < n && j < n) {
if (start[i] !== end[j]) {
return false
}
if ((start[i] === "L" && i < j) || (start[i] === "R" && i > j)) {
return false
}
i++
j++
}
}
// 其中一个字符串遍历到了末尾
while (i < n) {
if (start[i] !== "X") {
return false
}
i++
}
while (j < n) {
if (end[j] !== "X") {
return false
}
j++
}
return true
}
复杂度分析:
- 时间复杂度:O(n),其中 n 是字符串 start 和 end 的长度。我们需要遍历两个字符串各一次。
- 空间复杂度:O(1)。