leetcode-在LR字符串中交换相邻字符

83 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

题目描述

在一个由 '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'。

思路

拿到题目,显然无法直接模拟所有的情况来试探是否可以转换,所以思路就是去找充要条件。充分条件比较难一下子想到,我们就先考虑必要条件,就是当不符合什么情况的时候,一定无法从start转换成end。
最容易想到的当然是长度,长度不同肯定无法转换,稍微拓展一点,除了长度之外,由于只包含 'L' , 'R' 和 'X' 三种字符,那么必然每一种字符的数量也是相等的,这是第1个必要条件。
接下来我们看转换,"LX"替换"XL"、"XR"替换"RX",我们发现在替换的过程中,L可以往左走,R可以往右走,但是只能跨越 'X' , 'L' 和 'R'并不能相互跨越,所以,我们可以得到第2个必要条件:去掉所有'X'后,start和end仅由'L' 和 'R'组成,而且肯定是一样的。由于L可以往左走,R可以往右走,我们可以得到第3个必要条件,对于相同位置(非相同原始下标,是去掉X后字符串的下标)的'L',在原始的start和end中的下标记为i和j,一定满足i>=j;同样的,对于相同位置的'R',一定满足i<=j

我们整理上面的3个必要条件

  • 总长度相等,且3种字符数量相等
  • 去掉所有'X'后,start和end是一样的
  • 相同位置的'L',满足i>=j;相同位置的'R',满足i<=j

上面3个条件刚好组成了充分条件,这1点可以这样证明:条件1和条件2比较显然,对于条件3,相同位置的'L',又可以产生2种情况:

  1. i == j
  2. i > j 如果i == j,那么到当前,start和end肯定可以转换 如果i > j,造成到目前为止不相等,一定是前面'X'的数量不同,而'X'是可以跨越的,无论多少个X'。 所以,同时满足上面3个必要条件,同时也成了充分条件,这就是冲要条件。

编码技巧上,可以用i和j2个指针分别指向start和end的头,排除上面3个条件的不满足的情况,返回false,走到最后返回true即可。

Java版本代码

class Solution {
    public boolean canTransform(String start, String end) {
        char[] startArray = start.toCharArray();
        char[] endArray = end.toCharArray();
        int len = startArray.length;
        if (endArray.length != len) {
            // 长度不相等,肯定不满足条件
            return false;
        }
        for (int i = 0, j = 0; i < len || j < len;) {
            while (i < len && startArray[i] == 'X') {
                i++;
            }
            while (j < len && endArray[j] == 'X') {
                j++;
            }
            if (i == len || j == len) {
                return i == j;
            }
            if (startArray[i] != endArray[j]) {
                return false;
            }
            if (startArray[i] == 'L') {
                // L越交换越小,所以同位置的L肯定满足 i >= j
                if (i < j) {
                    return false;
                } else {
                    i++;
                    j++;
                }
            } else {
                // 此时 startArray[i] = endArray[j] = ‘R’
                // R越交换越大,所以同位置的R肯定满足 i <= j
                if (i > j) {
                    return false;
                } else {
                    i++;
                    j++;
                }
            }
        }
        return true;
    }
}