Stack Solution
class Solution:
def minRemoveToMakeValid(self, s: str) -> str:
""" tc O(N) sc O(N)
main idea: to make valid + since we can only remove => need to count to keep current substring balanced =>
how to minimize remove steps =>greedy ? XXX use stack to track open parathesis
1. push index into stack when we see a (
2. pop off stack previous index of ( when we see a ), otherwise set char of s at current index as ''
because this ) need to be removed
3. clear out stack, set char of s at indexes in the stack that has only (
"""
s = list(s)
st = []
for i,c in enumerate(s):
if c =='(':
st.append(i)
elif c == ')':
if st:
st.pop()
else:
s[i] = ''
while st:
s[st.pop()] = ''
return ''.join(s)
No stack Solution (Counter)
class Solution:
def minRemoveToMakeValid(self, s: str) -> str:
""" tc O(N) sc O(1) actually if res is considered extra space, will be sc O(N)
main idea: two round with counter for open and close parenthesis
1. one loop get all the closed parenthesis
2. second loop, check if current char is (, ), or other alpha
(1) if c == (, check if there are future ) to pair: yes, append ( to res, otherwise skip c
(2) if c == ), check if there are ( so far: if no, skip, otherwise, ) cnt -1 appenc c into res
(3) if c is alpha, append into res
"""
res = []
opens = closes = 0
for c in s:
if c == ')':
closes += 1 # cnt number of ) in the future at index 0
for c in s:
if c == '(':
opens += 1
if closes > 0:
closes -= 1 # can make a pair, future available ) decrease by 1
res.append(c)
elif c == ')':
# so far # of )in the future waiting to be paired
if opens > 0 :
opens -= 1 # cancel out previous paired (
res.append(c)
else:
closes -= 1 # remove invalid )
else:
res.append(c)
return ''.join(res)
Two pointer + Two Round inplace
class Solution:
def minRemoveToMakeValid(self, s: str) -> str:
""" tc O(N) sc O(1)
main idea:
1. from back to front,remove extra (, get the right ptr of non-empty char
2. start with right pointer, from front to back, remove extra )
3. return first non-empty substring
"""
s = list(s)
n = r = len(s)
balance = 0
for j in range(n-1,-1,-1):
if s[j] == ')':
balance += 1
elif s[j] == '(':
if balance == 0:
continue
balance -= 1
r -= 1
s[r] = s[j]
l = balance2 = 0
for i in range(r,n):
if s[i] == '(':
balance2 += 1
elif s[i] == ')':
if balance2 == 0:
continue
balance2 -= 1
s[l] = s[i]
l += 1
return ''.join(s[:l])