[LeetCode] 301. Remove Invalid Parentheses 移除非法括號
Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.
Note: The input string may contain letters other than the parentheses ( and ).
Examples:
"()())()" -> ["()()()", "(())()"]
"(a)())()" -> ["(a)()()", "(a())()"]
")(" -> [""]
Credits:
Subscribe to see which companies asked this question
思路:
題意是給出一個string,其中的小括號可能不配對,移除不配對的括號,返回所有的解。
首先,如何判斷括號是否合法。可以用棧,這也是棧這個數據結構的一個典型應用。也可用一個count計數器,遇到左括號++,右括號--,一旦count小於0,就說明不合法。比較推薦count方式,空間復雜度較低。
BFS: 枚舉去除的點,當找到後停止BFS樹的擴展(因為要去除最少括號,所以即使有其他的結果,也一定在同一層)
DFS: 統計左右括號能刪的個數,進行DFS。
Java: DFS
Calculate the number of invalid parentheses of the original string. Iterate through the string. Remove each character and DFS if the number of invalid parentheses decreases.
This solution is based on the fact that if we‘re on the right path to the optimal string, the number of invalid parentheses must always decrease.
Time complexity:
In the worst case, I could have some input like "))))))))", where I need to search through the entire string. The good thing is duplicates will be pruned by the hash set. Calculating mis-match takes O(n). So the overall time complexity is O(n^2).
class Solution { public List<String> removeInvalidParentheses(String s) { List<String> list = new ArrayList<>(); Set<String> visited = new HashSet<>(); removeInvalidParentheses(s, numberOfInvalid(s), list, visited); return list; } private void removeInvalidParentheses(String s, int invalid, List<String> list, Set<String> visited) { if (invalid == 0) { list.add(s); return; } for (int i = 0; i < s.length(); i++) { if (s.charAt(i) != ‘(‘ && s.charAt(i) != ‘)‘) { continue; } String child = s.substring(0, i) + s.substring(i + 1, s.length()); if (!visited.contains(child)) { visited.add(child); int next = numberOfInvalid(child); if (next < invalid) { removeInvalidParentheses(child, next, list, visited); } } } } private int numberOfInvalid(String s) { int open = 0; int close = 0; for (char c : s.toCharArray()) { if (c == ‘(‘) { open++; } else if (c == ‘)‘) { if (open == 0) { close++; } else { open--; } } } return open + close; } }
Java: BFS
Thought process:
BFS:
Graph definition:
Vertex: a candidate string.
Edge: two strings s1 and s2 have an edge if s1 equals s2 with one parenthesis deleted.
Put string into a queue.
For the current size of the queue, poll a string from the queue.
Iterate through the string. For each character, remove it, and check if the parentheses are valid.
If so, iterate over current level and return the result.
If not, offer the new string to the queue.
Time complexity:
Say the string‘s length is n. For every character, the choice is to keep or remove. So there are 2^n total states to check. Check if a string is valid is O(1). So the overall time complexity is O(2^n).
class Solution { public List<String> removeInvalidParentheses(String s) { List<String> list = new ArrayList<>(); Queue<String> queue = new LinkedList<>(); queue.offer(s); Set<String> visited = new HashSet<>(); visited.add(s); boolean found = false; while (!found && !queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { String str = queue.poll(); if (isValid(str)) { list.add(str); found = true; continue; } for (int j = 0; j < str.length(); j++) { if (str.charAt(j) != ‘(‘ && str.charAt(j) != ‘)‘) { continue; } String child = str.substring(0, j) + str.substring(j + 1); if (!visited.contains(child)) { queue.offer(child); visited.add(child); } } } } return list; } private boolean isValid(String s) { int open = 0; for (char c : s.toCharArray()) { if (c == ‘(‘) { open++; } else if (c == ‘)‘) { if (open == 0) { return false; } open--; } } return open == 0; } }
Python: DFS
class Solution(object): def removeInvalidParentheses(self, s): """ :type s: str :rtype: List[str] """ def dfs(s): mi = calc(s) if mi == 0: return [s] ans = [] for x in range(len(s)): if s[x] in (‘(‘, ‘)‘): ns = s[:x] + s[x+1:] if ns not in visited and calc(ns) < mi: visited.add(ns) ans.extend(dfs(ns)) return ans def calc(s): a = b = 0 for c in s: a += {‘(‘ : 1, ‘)‘ : -1}.get(c, 0) b += a < 0 a = max(a, 0) return a + b visited = set([s]) return dfs(s)
Python: BFS
class Solution(object): def removeInvalidParentheses(self, s): """ :type s: str :rtype: List[str] """ def calc(s): a = b = 0 for c in s: a += {‘(‘ : 1, ‘)‘ : -1}.get(c, 0) b += a < 0 a = max(a, 0) return a + b visited = set([s]) ans = [] queue = collections.deque([s]) done = False while queue: t = queue.popleft() mi = calc(t) if mi == 0: done = True ans.append(t) if done: continue for x in range(len(t)): if t[x] not in (‘(‘, ‘)‘): continue ns = t[:x] + t[x+1:] if ns not in visited and calc(ns) < mi: visited.add(ns) queue.append(ns) return ans
Python: DFS
class Solution(object): def removeInvalidParentheses(self, s): """ :type s: str :rtype: List[str] """ if not s: return [‘‘] left_remove = right_remove = 0 for c in s: if c == ‘(‘: left_remove += 1 elif c == ‘)‘: if left_remove: left_remove -= 1 else: right_remove += 1 ans = set() self.dfs(0, left_remove, right_remove, 0, ‘‘, s, ans) return list(ans) def dfs(self, index, left_remove, right_remove, left_pare, cur, s, ans): if left_remove < 0 or right_remove < 0 or left_pare < 0: return if index == len(s): if left_remove == right_remove == left_pare == 0: ans.add(cur) return if s[index] == ‘(‘: self.dfs(index + 1, left_remove - 1, right_remove, left_pare, cur, s, ans) self.dfs(index + 1, left_remove, right_remove, left_pare + 1, cur + s[index], s, ans) elif s[index] == ‘)‘: self.dfs(index + 1, left_remove, right_remove - 1, left_pare, cur, s, ans) self.dfs(index + 1, left_remove, right_remove, left_pare - 1, cur + s[index], s, ans) else: self.dfs(index + 1, left_remove, right_remove, left_pare, cur + s[index], s, ans)
Python: BFS
class Solution(object): def removeInvalidParentheses(self, s): """ :type s: str :rtype: List[str] """ if not s: return [‘‘] q, ans, vis = [s], [], set([s]) found = False while q: cur = q.pop(0) if self.isValidParentheses(cur): found = True ans.append(cur) elif not found: for i in xrange(len(cur)): if cur[i] == ‘(‘ or cur[i] == ‘)‘: t = cur[:i] + cur[i + 1:] if t not in vis: q.append(t) vis.add(t) return ans def isValidParentheses(self, s): cnt = 0 for c in s: if c == ‘(‘: cnt += 1 elif c == ‘)‘: if cnt == 0: return False cnt -= 1 return cnt == 0
Python: BFS, concise
class Solution(object): def removeInvalidParentheses(self, s): """ :type s: str :rtype: List[str] """ if not s: return [‘‘] q = {s} while q: ans = filter(self.isValidParentheses,q) if ans: return ans q = {cur[:i] + cur[i + 1:] for cur in q for i in xrange(len(cur))} def isValidParentheses(self, s): cnt = 0 for c in s: if c == ‘(‘: cnt += 1 elif c == ‘)‘: if cnt == 0: return False cnt -= 1 return cnt == 0
C++:
class Solution { public: vector<string> removeInvalidParentheses(string s) { vector<string> res; unordered_set<string> visited{{s}}; queue<string> q{{s}}; bool found = false; while (!q.empty()) { string t = q.front(); q.pop(); if (isValid(t)) { res.push_back(t); found = true; } if (found) continue; for (int i = 0; i < t.size(); ++i) { if (t[i] != ‘(‘ && t[i] != ‘)‘) continue; string str = t.substr(0, i) + t.substr(i + 1); if (!visited.count(str)) { q.push(str); visited.insert(str); } } } return res; } bool isValid(string t) { int cnt = 0; for (int i = 0; i < t.size(); ++i) { if (t[i] == ‘(‘) ++cnt; else if (t[i] == ‘)‘ && --cnt < 0) return false; } return cnt == 0; } };
[LeetCode] 301. Remove Invalid Parentheses 移除非法括號