Intuition:
- Use DFS to recursively either remove the character or just continue.
Gotchas:
- The program expects empty string in the answer if there are no other matches
- non-parenthesis characters is like a no-op character, that moves the iterator without doing anything.
- The answer needs to be in set to avoid duplicates
- left parenthesis(L) has a preferential consideration over right parenthesis(R) since R is an invariant if there is more R than L at any given position.
Base case:
- The resulting answer should have a matching number of parenthesis.
- Iteration ends when the iteration reaches the end of the string
Solution 1 (One pass, no extra memory) :
class Solution:
def removeInvalidParentheses(self, s: str) -> List[str]:
ans = set()
N = len(s)
length = 0
def traverse(left, right, i, stack):
nonlocal s, ans, N, length
if i == N:
if stack and left == 0 and right == 0: #3
if len(stack) > length:
ans = {stack}
length = len(stack)
elif len(stack) == length:
ans.add(stack)
else:
if s[i] == '(':
if right==0:
traverse(left+1, right, i+1, stack+s[i])
traverse(left, right, i+1, stack)
elif s[i] == ')':
if left > 0:
traverse(left-1, right, i+1, stack+s[i])
traverse(left, right, i+1, stack)
else:
traverse(left, right, i+1, stack+s[i])
traverse(0,0,0,"")
return ans or [""] #1
Solution 2 (Two Pass, calculate the invariants first)
class Solution:
def removeInvalidParentheses(self, s: str) -> List[str]:
ans = set()
N = len(s)
left_rem, right_rem = 0, 0
for i in range(N):
if s[i] == '(':
left_rem +=1 # Preferential treatment of L
elif s[i] == ')':
if left_rem > 0:
left_rem -= 1
else:
right_rem += 1
def dfs(i, left, right, left_rem, right_rem, stack):
nonlocal ans
if i == N:
if left_rem == 0 and right_rem == 0:
ans.add(stack)
return
else:
if s[i] == "(":
if left_rem > 0:
dfs(i+1, left, right, left_rem-1, right_rem, stack)
# Preferential treatment of L. No condition for considering it
dfs(i+1, left+1, right, left_rem, right_rem, stack+s[i])
elif s[i] == ")":
if right_rem > 0:
dfs(i+1, left, right, left_rem, right_rem-1, stack)
if left > right:
dfs(i+1, left, right+1, left_rem, right_rem, stack+s[i])
else:
dfs(i+1, left, right, left_rem, right_rem, stack+s[i])
dfs(0,0,0,left_rem,right_rem,"")
return ans
Complexity Analysis:
O(2^N) since for each character we have an option of either considering or discarding it. But in the second solution, pruning is done much actively, O(2^(k)) where k = '# of invariants'
Comments
comments powered by Disqus