{x}
blog image

Move Pieces to Obtain a String

You are given two strings start and target, both of length n. Each string consists only of the characters 'L', 'R', and '_' where:

  • The characters 'L' and 'R' represent pieces, where a piece 'L' can move to the left only if there is a blank space directly to its left, and a piece 'R' can move to the right only if there is a blank space directly to its right.
  • The character '_' represents a blank space that can be occupied by any of the 'L' or 'R' pieces.

Return true if it is possible to obtain the string target by moving the pieces of the string start any number of times. Otherwise, return false.

 

Example 1:

Input: start = "_L__R__R_", target = "L______RR"
Output: true
Explanation: We can obtain the string target from start by doing the following moves:
- Move the first piece one step to the left, start becomes equal to "L___R__R_".
- Move the last piece one step to the right, start becomes equal to "L___R___R".
- Move the second piece three steps to the right, start becomes equal to "L______RR".
Since it is possible to get the string target from start, we return true.

Example 2:

Input: start = "R_L_", target = "__LR"
Output: false
Explanation: The 'R' piece in the string start can move one step to the right to obtain "_RL_".
After that, no pieces can move anymore, so it is impossible to obtain the string target from start.

Example 3:

Input: start = "_R", target = "R_"
Output: false
Explanation: The piece in the string start can move only to the right, so it is impossible to obtain the string target from start.

 

Constraints:

  • n == start.length == target.length
  • 1 <= n <= 105
  • start and target consist of the characters 'L', 'R', and '_'.

Solution Explanation for "Move Pieces to Obtain a String"

This problem asks whether it's possible to transform string start into string target by moving 'L' and 'R' pieces across underscores ('_'). The crucial observation is that the relative order of 'L' and 'R' pieces must remain the same, and 'L' pieces can only move left, 'R' pieces only right.

Approach:

The most efficient approach involves two pointers and avoids unnecessary manipulations of the strings. We iterate through both start and target simultaneously, ignoring underscores initially.

  1. Preprocessing (Optional but Helpful): Extract the positions of 'L' and 'R' characters from both strings into separate lists of tuples (character, index). This helps in directly comparing the positions and types of pieces.

  2. Length Check: If the number of 'L' and 'R' pieces differs between start and target, it's immediately impossible to transform one into the other.

  3. Iterative Comparison: Use two pointers to iterate through the lists of 'L' and 'R' positions for start and target. In each step:

    • If the character types don't match (L vs R), it's impossible.
    • If a character is 'L', its index in start must be greater than or equal to its index in target (it can only move left).
    • If a character is 'R', its index in start must be less than or equal to its index in target (it can only move right).
    • If any of these conditions fail, it's impossible to transform start to target.
  4. Return True: If the loop completes without finding any inconsistencies, it's possible.

Time Complexity Analysis:

  • The preprocessing step (creating the lists of tuples) takes O(N) time, where N is the length of the strings.
  • The iterative comparison step also takes O(M) time, where M is the number of 'L' and 'R' pieces (M <= N).

Therefore, the overall time complexity is O(N), dominated by the string traversal. The space complexity is O(M) in the worst case (if most characters are 'L' or 'R'), which is still linear with respect to the input size. In practice, it often uses less space than a solution involving string manipulation.

Code Examples (Python):

Solution 1 (Using lists of tuples):

class Solution:
    def canChange(self, start: str, target: str) -> bool:
        a = [(v, i) for i, v in enumerate(start) if v != '_']
        b = [(v, i) for i, v in enumerate(target) if v != '_']
        if len(a) != len(b):
            return False
        for (c, i), (d, j) in zip(a, b):
            if c != d:
                return False
            if c == 'L' and i < j:
                return False
            if c == 'R' and i > j:
                return False
        return True

Solution 2 (In-place with two pointers, more concise):

class Solution:
    def canChange(self, start: str, target: str) -> bool:
        n = len(start)
        i = j = 0
        while 1:
            while i < n and start[i] == '_':
                i += 1
            while j < n and target[j] == '_':
                j += 1
            if i >= n and j >= n:
                return True
            if i >= n or j >= n or start[i] != target[j]:
                return False
            if start[i] == 'L' and i < j:
                return False
            if start[i] == 'R' and i > j:
                return False
            i, j = i + 1, j + 1

The other languages (Java, C++, Go, TypeScript) would follow a very similar structure to these Python solutions, adapting the syntax and data structures accordingly. The core logic and time/space complexity remain the same.