-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path0301-remove-invalid-parentheses.py
More file actions
128 lines (107 loc) · 4.84 KB
/
0301-remove-invalid-parentheses.py
File metadata and controls
128 lines (107 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from typing import List, Set
import unittest
# https://leetcode.com/problems/remove-invalid-parentheses/
# python3 -m unittest backtracking/0301-remove-invalid-parentheses.py
class Solution(unittest.TestCase):
# # Approach 1: BFS (Breadth-First Search)
# # Generate all possible strings by removing one parenthesis at a time
# # Use BFS to ensure we find the minimum number of removals
# # Time: O(2^n) where n is the length of string (each char can be kept or removed)
# # Space: O(2^n) for storing all possible strings in the queue
# def removeInvalidParentheses(self, s: str) -> List[str]:
# def is_valid(string: str) -> bool:
# count = 0
# for char in string:
# if char == "(":
# count += 1
# elif char == ")":
# count -= 1
# if count < 0:
# return False
# return count == 0
# result: List[str] = []
# visited: Set[str] = set()
# queue = deque([s])
# visited.add(s)
# found = False
# while queue:
# current = queue.popleft()
# if is_valid(current):
# result.append(current)
# found = True
# # If we found valid strings at this level, don't go deeper
# if found:
# continue
# # Try removing each parenthesis
# for i in range(len(current)):
# if current[i] not in ("(", ")"):
# continue
# next_str = current[:i] + current[i + 1 :]
# if next_str not in visited:
# visited.add(next_str)
# queue.append(next_str)
# return result if result else [""]
# Approach 2: Backtracking (Optimized)
# First calculate how many '(' and ')' need to be removed
# Then use backtracking to generate all valid combinations
# Time: O(2^n) where n is the length of string
# Space: O(n) for recursion depth
def removeInvalidParentheses(self, s: str) -> List[str]:
# Step 1: Count how many left and right parentheses to remove
left_to_remove = 0
right_to_remove = 0
for char in s:
if char == "(":
left_to_remove += 1
elif char == ")":
if left_to_remove > 0:
left_to_remove -= 1
else:
right_to_remove += 1
result: Set[str] = set()
def backtrack(index: int, left_count: int, right_count: int, left_rem: int, right_rem: int, expr: str):
# index: current position in string
# left_count: number of '(' in current expression
# right_count: number of ')' in current expression
# left_rem: number of '(' still need to remove
# right_rem: number of ')' still need to remove
# expr: current expression being built
# Base case: reached end of string
if index == len(s):
# Valid if we removed all invalid parentheses and counts match
if left_rem == 0 and right_rem == 0 and left_count == right_count:
result.add(expr)
return
char = s[index]
# Option 1: Remove current character (if it's a parenthesis and we need to remove)
if char == "(" and left_rem > 0:
backtrack(index + 1, left_count, right_count, left_rem - 1, right_rem, expr)
elif char == ")" and right_rem > 0:
backtrack(index + 1, left_count, right_count, left_rem, right_rem - 1, expr)
# Option 2: Keep current character
if char == "(":
backtrack(index + 1, left_count + 1, right_count, left_rem, right_rem, expr + char)
elif char == ")":
# Only add ')' if it doesn't make expression invalid
if right_count < left_count:
backtrack(index + 1, left_count, right_count + 1, left_rem, right_rem, expr + char)
else:
# Regular character, always keep
backtrack(index + 1, left_count, right_count, left_rem, right_rem, expr + char)
backtrack(0, 0, 0, left_to_remove, right_to_remove, "")
return list(result) if result else [""]
def test(self):
for s, expected in [
("()())()", ["(())()", "()()()"]),
("(a)())()", ["(a())()", "(a)()()"]),
(")(", [""]),
("", [""]),
("()", ["()"]),
("()())", ["(())", "()()"]),
("())", ["()"]),
("(()", ["()"]),
]:
output = self.removeInvalidParentheses(s)
expected.sort()
output.sort()
self.assertEqual(expected, output, f"expected: {expected}, output: {output}")