问题:
给定一个字符串,包含左右小括号+字母。
对该字符串进行【括号删减】,使得 字符串中括号完全匹配。"( )"
求最少删减字符,能得到的所有完全匹配的字符串。
Example 1: Input: "()())()" Output: ["()()()", "(())()"] Example 2: Input: "(a)())()" Output: ["(a)()()", "(a())()"] Example 3: Input: ")(" Output: [""]
解法:Backtracking(回溯算法)
前期准备:
遍历字符串,遇到"(" count++,遇到")" count--
那么匹配的正常字符串的count变化应该总是符合:count>=0....最终count==0
若期间只要有count<0,那么这时一定多余出来一个")"
计算这样多余出来的")"的个数:minright
去掉这些不符合条件的")",最后,得到count>0,则为多出来的"(",计数为minleft
Backtracking:
状态:
- 到目前位置pos为止,删减括号,得到的正确字符串path。
- 这时,剩下可删减的"("个数:left
- 剩下可删减的")"个数:right
- 当前的count状态,由于path为正确字符串,那么count一定>=0,若<0,则不符合要求,直接返回。
选择:
- 当前字符:s[pos]
- "(" 且 还可删减 left>0:对s[pos]删除:path, count, left--, right
- ")" 且 还可删减 right>0:对s[pos]删除:path, count, left, right--
- 不删减:若s[pos]:path+s[pos], count(做以下处理), left, right
- "(" :count++
- ")" :count--
递归退出条件:
- pos==s.length
- 若left==right==count==0 则 res.push_back(path),再return
- 否则直接return
- 若count<0, 直接return。当前path已经不满足括号匹配要求。
代码参考:
1 class Solution { 2 public: 3 // int cc = 0; 4 // void print_intend() { 5 // for(int i=0; i<cc; i++) { 6 // printf(" "); 7 // } 8 // } 9 void backtrack(unordered_set<string>& res, string path, int pos, int count, int left, int right, string& s) { 10 if(count<0) return; 11 if(pos==s.length()) { 12 if(left==0 && right==0 && count==0) { 13 res.insert(path); 14 // print_intend(); 15 // printf("return res.last:%s. ", path.c_str()); 16 } 17 return; 18 } 19 if(s[pos]=='(' && left>0) { 20 // print_intend(); 21 // printf("count:%d, left:%d, right:%d. path:%s ", count, left-1, right, path.c_str()); 22 // cc++; 23 backtrack(res, path, pos+1, count, left-1, right, s); 24 // cc--; 25 } else if(s[pos]==')' && right>0) { 26 // print_intend(); 27 // printf("count:%d, left:%d, right:%d. path:%s ", count, left, right-1, path.c_str()); 28 // cc++; 29 backtrack(res, path, pos+1, count, left, right-1, s); 30 // cc--; 31 } 32 switch(s[pos]) { 33 case '(': count++; break; 34 case ')': count--; break; 35 default: break; 36 } 37 // print_intend(); 38 // printf("--count:%d, left:%d, right:%d. path:%s ", count, left, right, path.c_str()); 39 // cc++; 40 backtrack(res, path+s[pos], pos+1, count, left, right, s); 41 // cc--; 42 return; 43 } 44 vector<string> removeInvalidParentheses(string s) { 45 unordered_set<string> res; 46 string path; 47 int minleft = 0, minright = 0, count = 0; 48 for(char c:s) { 49 switch(c) { 50 case '(': count++; break; 51 case ')': count--; break; 52 default: break; 53 } 54 if(count<0) { 55 minright++;//')' 56 count++; 57 } 58 } 59 minleft=count;//'(' 60 backtrack(res, path, 0, 0, minleft, minright, s); 61 return vector<string>(res.begin(), res.end()); 62 } 63 };