刷了一個困難題,一如既往做不出來,然後看題解,然後再自己打一遍…記錄這個題的原因是,這其實是一類題目!!!先看看題目再分析。
題目描述:
刪除最小數量的無效括號,使得輸入的字符串有效,返回所有可能的結果。
說明: 輸入可能包含了除 ( 和 ) 以外的字符。
示例 1:
輸入: “()())()”
輸出: ["()()()", “(())()”]
示例 2:
輸入: “(a)())()”
輸出: ["(a)()()", “(a())()”]
示例 3:
輸入: “)(”
輸出: [""]
分析題目:
這真的是一類題,題目具有的特徵:
1.求的是一個子集
2.且子集滿足一定的條件
這類題目可以用一個方法,就是DFS
關於這題DFS的分析:
1.DFS遍歷的行爲?刪括號
2.什麼情況下刪?就是當左括號或者右括號有多的時候,正好當前遍歷的又是個多的括號,就刪!!!之後再繼續進行DFS遍歷刪除
3.出口是什麼?當沒有多餘的括號的時候!!!但注意此時還需要檢查一下當前的字符串是否合法(即左右括號是否匹配!)
解題步驟:
1. 先統計多餘的括號,注意並不是循環一遍統計左右括號個數,然後多的一方就是多餘的。
如 left= 2,right = 3,就認爲右括號多一個,因爲可能之前的不匹配!!!
正確的統計方法是,當遇到左括號left++,遇到右括號時,若left > 0 就left --,說明一對括號匹配消除,若left == 0 ,right++,那麼這樣留下來的就是多餘的括號,沒有被匹配的括號!!!
2. 然後開始DFS,從第一個字符串開始,若當前符號是多餘需要刪除,則刪除,
如:此時DFS遍歷時left = 0,right = 1,當前是s[ i ] 爲左括號則跳過,若爲右括號則刪除,
然後對後面進行遞歸DFS。
3. 直到left 爲 0 ,right爲 0,進行檢查,匹配加入set< string >
代碼如下:
class Solution {
public:
bool checks(string s){
int left = 0;
for(int i = 0;i < s.size();i++){
if(s[i] == '(') left++;
else if(s[i] == ')'){
if(!left) return false;
else left--;
}
}
return true;
}
void dfs(set<string> &result,string s,int left,int right,int index){
if(!left&&!right){
if(checks(s)) result.insert(s);
return ;
}
for(int i = index;i < s.size();i++){
if(s[i] == '('&&left) dfs(result,s.substr(0,i)+s.substr(i+1,s.size()-i-1),left-1,right,i);
else if(s[i] == ')'&&right) dfs(result,s.substr(0,i)+s.substr(i+1,s.size()-i-1),left,right-1,i);
}
}
vector<string> removeInvalidParentheses(string s) {
int left = 0;
int right = 0;
for(int i = 0;i < s.size();i++){
if(s[i] == '(') left++;
else if(s[i] == ')'){
if(left > 0) left--;
else right++;
}
}
set<string> result;
dfs(result,s,left,right,0);
return vector<string>(result.begin(),result.end());
}
};
總結:
關於DFS不要怕,步驟就是,首先遞歸的操作,其次遞歸的出口!!!