[LeetCode] Swap Adjacent in LR String 交换LR字符串中的相邻项

 

In a string composed of 'L''R', and 'X' characters, like "RXXLRXRXL", a move consists of either replacing one occurrence of "XL" with "LX", or replacing one occurrence of "RX" with "XR". Given the starting string start and the ending string end, return True if and only if there exists a sequence of moves to transform one string to the other.

Example:

Input: start = "RXXLRXRXL", end = "XRLXXRRLX"
Output: True
Explanation:
We can transform start to end following these steps:
RXXLRXRXL ->
XRXLRXRXL ->
XRLXRXRXL ->
XRLXXRRXL ->
XRLXXRRLX

Note:

  1. 1 <= len(start) = len(end) <= 10000.
  2. Both start and end will only consist of characters in {'L', 'R', 'X'}.

 

这道题给了我们一个只含有L,R,X三个字符的字符串,然后说有两种操作,一种是把 “XL” 变成 “LX”,另一种是把 “RX” 变成 “XR”。博主刚开始没有读题意,以为二者是可以互换的,错误的认为认为 “LX” 也能变成 “XL”,其实题目这种变换是单向,这种单向关系就是解题的关键,具体来说,就是要把start字符串变成end字符串的话,L只能往前移动,因为是把 “XL” 变成 “LX”,同样,R只能往后移动,因为是把 “RX” 变成 “XR”。题目给的那个例子并不能很好的说明问题,博主之前那种双向变换的错误认知会跪在这个例子:

start = “XXRXXLXXXX”
end  = “XXXXRXXLXX”

我们观察这个test case,可以发现start中的R可以往后移动,没有问题,但是start中的L永远无法变到end中L的位置,因为L只能往前移。这道题被归类为brainteaser,估计就是因为要观察出这个规律吧。那么搞明白这个以后,我们其实可以用双指针来解题,思路是,我们每次分别找到start和end中非X的字符,如果二者不相同的话,直接返回false,想想问什么?这是因为不论是L还是R,其只能跟X交换位置,L和R之间是不能改变相对顺序的,所以如果分别将start和end中所有的X去掉后的字符串不相等的话,那么就永远无法让start和end相等了。这个判断完之后,就来验证L只能前移,R只能后移这个限制条件吧,当i指向start中的L时,那么j指向end中的L必须要在前面,所以如果i小于j的话,就不对了,同理,当i指向start中的R,那么j指向end中的R必须在后面,所以i大于j就是错的,最后别忘了i和j同时要自增1,不然死循环了,参见代码如下:

 

解法一:

class Solution {
public:
    bool canTransform(string start, string end) {
        int n = start.size(), i = 0, j = 0;
        while (i < n && j < n) {
            while (i < n && start[i] == 'X') ++i;
            while (j < n && end[j] == 'X') ++j;
            if (start[i] != end[j]) return false;
            if ((start[i] == 'L' && i < j) || (start[i] == 'R' && i > j)) return false;
            ++i; ++j;
        }
        return true;
    }
};

 

下面这种解法也挺巧妙的,这里我们使用两个计数器cntL和cntR,分别来统计L和R出现的次数,统计方法时,start中出现了L或R,计数器自增1,end中出现了L或R,计数器自减1。注意我们检测的顺序很重要,由于start中的R必须在end中的R前面,所以我们要先检测start中的R,同理,由于end中的L必须要在start中的L前面,所以我们要先检测end中的L,那么四个if写完后,如果cntL或者cntR中有任何一个小于0了,说明限制条件被打破了,返回false,或者当二者都大于0的时候,说明此时不匹配了,参见上面解法中对于去掉所有的X的解释,一个道理,说明L和R的相对顺序不同了,那么也是false。最终for循环退出后,如果cntL和cntR均为0的时候,才返回true,否则就是false,参见代码如下:

 

解法二:

class Solution {
public:
    bool canTransform(string start, string end) {
        int n = start.size(), cntL = 0, cntR = 0;
        for (int i = 0; i < n; ++i) {
            if (start[i] == 'R') ++cntR;
            if (end[i] == 'L') ++cntL;
            if (start[i] == 'L') --cntL;
            if (end[i] == 'R') --cntR;
            if (cntL < 0 || cntR < 0 || cntL * cntR != 0) return false;
        }
        return cntL == 0 && cntR == 0;
    }
};

 

参考资料:

https://leetcode.com/problems/swap-adjacent-in-lr-string/solution/

https://leetcode.com/problems/swap-adjacent-in-lr-string/discuss/126397/Simple-C++-solution-12ms-O(N)-time-and-O(1)-space

https://leetcode.com/problems/swap-adjacent-in-lr-string/discuss/113789/Simple-Java-one-pass-O(n)-solution-with-explaination

 

    原文作者:Grandyang
    原文地址: http://www.cnblogs.com/grandyang/p/9001474.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞