838. Push Dominoes - Explanation

Problem Link



1. Brute Force

class Solution:
    def pushDominoes(self, dominoes: str) -> str:
        n = len(dominoes)
        res = list(dominoes)

        for i in range(n):
            if dominoes[i] != '.':
                continue

            l, r = i - 1, i + 1

            while l >= 0 and dominoes[l] == '.':
                l -= 1

            while r < n and dominoes[r] == '.':
                r += 1

            left_force = dominoes[l] if l >= 0 else None
            right_force = dominoes[r] if r < n else None

            if left_force == 'R' and right_force == 'L':
                if (i - l) < (r - i):
                    res[i] = 'R'
                elif (r - i) < (i - l):
                    res[i] = 'L'
            elif left_force == 'R':
                res[i] = 'R'
            elif right_force == 'L':
                res[i] = 'L'

        return "".join(res)

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n)O(n) for only the output string.

2. Force From Left & Right

class Solution:
    def pushDominoes(self, dominoes: str) -> str:
        n = len(dominoes)
        left = [float('inf')] * n
        right = [float('inf')] * n
        res = list(dominoes)

        force = float('inf')
        for i in range(n):
            if dominoes[i] == 'R':
                force = 0
            elif dominoes[i] == 'L':
                force = float('inf')
            else:
                force += 1
            right[i] = force

        force = float('inf')
        for i in range(n - 1, -1, -1):
            if dominoes[i] == 'L':
                force = 0
            elif dominoes[i] == 'R':
                force = float('inf')
            else:
                force += 1
            left[i] = force

        for i in range(n):
            if left[i] < right[i]:
                res[i] = 'L'
            elif right[i] < left[i]:
                res[i] = 'R'

        return "".join(res)

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

3. Simulation (Queue)

class Solution:
    def pushDominoes(self, dominoes: str) -> str:
        dom = list(dominoes)
        q = deque()

        for i, d in enumerate(dom):
            if d != ".":
                q.append((i, d))

        while q:
            i, d = q.popleft()

            if d == "L" and i > 0 and dom[i - 1] == ".":
                q.append((i - 1, "L"))
                dom[i - 1] = "L"
            elif d == "R":
                if i + 1 < len(dom) and dom[i + 1] == ".":
                    if i + 2 < len(dom) and dom[i + 2] == "L":
                        q.popleft()
                    else:
                        q.append((i + 1, "R"))
                        dom[i + 1] = "R"

        return "".join(dom)

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

4. Iteration (Greedy)

class Solution:
    def pushDominoes(self, dominoes: str) -> str:
        res = []
        dots = 0
        R = False

        for d in dominoes:
            if d == '.':
                dots += 1
            elif d == 'R':
                if R:
                    # Previous was 'R', and current is also 'R'.
                    # Append 'R' for all the dots between them.
                    res.append('R' * (dots + 1))
                elif dots > 0:
                    # Previous was not 'R'. The previous dots remain unchanged.
                    res.append('.' * dots)
                dots = 0
                R = True  # Current is 'R'
            else:
                if R:
                    # Append the previous 'R'.
                    res.append('R')
                    if dots > 0:
                        # Half the dots are affected by the previous 'R'.
                        res.append('R' * (dots // 2))

                        # Add a '.' if there's an odd number of dots.
                        if (dots % 2) != 0:
                            res.append('.')

                        # Append half the dots as 'L'.
                        res.append('L' * (dots // 2))

                    # Append the current 'L'.
                    res.append('L')
                    R, dots = False, 0
                else:
                    # There is no 'R' on the left.
                    # Append 'L' for all the dots and the current 'L'.
                    res.append('L' * (dots + 1))
                    dots = 0

        if R:
            # Trailing dots are affected by the last 'R'.
            res.append('R' * (dots + 1))
        else:
            # Trailing dots remain unchanged as there is no previous 'R'.
            res.append('.' * dots)

        return ''.join(res)

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n) for only the output string.