[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 <= len(start) = len(end) <= 10000
.- 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 = "XXXXR
我們觀察這個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; } };
參考資料: