Problem of The Day: Push Dominoes
Problem Statement
Intuition
To simulate how dominoes fall over time, we need to consider the influence of each ‘R’ (right push) and ‘L’ (left push) on the dominoes around them. A domino gets pushed by its nearest force unless equal forces cancel out. Therefore, tracking the distance from the closest ‘R’ and ‘L’ is crucial to determining the final state of each domino.
Approach
- Create three lists:
right
,left
, andres
, initialized with the input string. - Traverse from left to right to simulate rightward forces:
- Whenever an ‘R’ is encountered, start counting distance (
force
) from that point. - Update the
right
list with the distance to the nearest ‘R’ for each domino.
- Whenever an ‘R’ is encountered, start counting distance (
- Traverse from right to left to simulate leftward forces:
- Whenever an ‘L’ is encountered, start counting distance (
force
) from that point. - Update the
left
list with the distance to the nearest ‘L’ for each domino.
- Whenever an ‘L’ is encountered, start counting distance (
- Iterate over each domino:
- If the domino is ‘.’, compare the left and right forces:
- If they are equal, do nothing (forces cancel).
- If left is stronger, set to ‘L’.
- If right is stronger, set to ‘R’.
- If the domino is ‘.’, compare the left and right forces:
- Return the final state as a string.
Complexity
-
Time complexity:
\(O(n)\)
Each domino is visited a constant number of times. -
Space complexity:
\(O(n)\)
Additional space is used forright
,left
, andres
arrays.
Code
class Solution:
def pushDominoes(self, dominoes: str) -> str:
right = list(dominoes)
left = list(dominoes)
res = list(dominoes)
N = len(dominoes)
force = 0
curr = ''
for i in range(N):
if dominoes[i] == 'R':
curr = 'R'
force = 0
elif dominoes[i] == 'L':
curr = 'L'
force = 0
if curr == 'R':
right[i] = force
force += 1
curr = ''
for i in range(N - 1, -1, -1):
if dominoes[i] == 'R':
curr = 'R'
force = 0
elif dominoes[i] == 'L':
curr = 'L'
force = 0
if curr == 'L':
left[i] = force
force += 1
for i in range(N):
if dominoes[i] == '.':
if left[i] == right[i]:
continue
l_val = float('inf') if str(left[i]) in 'RL.' else left[i]
r_val = float('inf') if str(right[i]) in 'RL.' else right[i]
if l_val < r_val:
res[i] = 'L'
else:
Editorial
Approach #1: Adjacent Symbols [Accepted]
class Solution(object):
def pushDominoes(self, dominoes):
symbols = [(i, x) for i, x in enumerate(dominoes) if x != '.']
symbols = [(-1, 'L')] + symbols + [(len(dominoes), 'R')]
ans = list(dominoes)
for (i, x), (j, y) in zip(symbols, symbols[1:]):
if x == y:
for k in xrange(i+1, j):
ans[k] = x
elif x > y: #RL
for k in xrange(i+1, j):
ans[k] = '.LR'[cmp(k-i, j-k)]
return "".join(ans)
Approach #2: Calculate Force [Accepted]
class Solution(object):
def pushDominoes(self, dominoes):
N = len(dominoes)
force = [0] * N
# Populate forces going from left to right
f = 0
for i in xrange(N):
if dominoes[i] == 'R': f = N
elif dominoes[i] == 'L': f = 0
else: f = max(f-1, 0)
force[i] += f
# Populate forces going from right to left
f = 0
for i in xrange(N-1, -1, -1):
if dominoes[i] == 'L': f = N
elif dominoes[i] == 'R': f = 0
else: f = max(f-1, 0)
force[i] -= f
return "".join('.' if f==0 else 'R' if f > 0 else 'L'
for f in force)