題目大意
給定一個字符串,可能會包括’(‘,’)’,和其他字符,得到所有合理的記過,實際上也就是左右括號匹配問題。
例子:
“()())()” -> [“()()()”, “(())()”]
“(a)())()” -> [“(a)()()”, “(a())()”]
“)(” -> [“”]
解題思路
參考:https://discuss.leetcode.com/topic/34875/easy-short-concise-and-fast-java-dfs-3-ms-solution
We all know how to check a string of parentheses is valid using a stack. Or even simpler use a counter.
The counter will increase when it is ‘(‘ and decrease when it is ‘)’. Whenever the counter is negative, we have more ‘)’ than ‘(‘ in the prefix.
意思是檢查一個字符串的左右括號是否合理匹配的最簡單的方法就是從左到右遍歷字符串,一直要維持這個prefix的左括號的數目不大於右括號的數目。一旦右括號數目大於左括號的數目就沒有必要繼續往下看了,必須把多出來的右括號刪掉。
不需要用stack,只要用一個計數器,這個計數器記錄遍歷至當前字符時,’(‘與’)’的數量差,合理字符串是不可能出現counter<0的情況的,一旦遇到counter<0就說明需要刪掉某個’)’使得字符串重新獲得合理狀態。
那麼,刪掉那個右括號呢?
用個例子解釋:
刪除’)’的時候,如果有一串連續的’)’,只需要刪除這串’)’中的任意一個都能得到一樣的合理字符串,爲了避免得到重複的結果,約定只刪除第一個’)’。
刪除的時候用DFS的思想,首先刪掉第一個多出來的右括號,再遞歸處理。
經過上述處理,已經將左括號數目>右括號數目的case fix了,但是其實counter>0也是代表字符串是不合理的,如‘(()(()’,需要刪掉’(‘,最簡單的方法就是從右到左再run一遍,很妙的想法是求原字符串的逆序,如”((()”會變成”)))(“原字符串在本算法裏面是合理的,但是逆字符串卻不是合理的,這樣直接遞歸就能處理這種情況了,只不過逆序之後實際的左括號是’)’,右括號是’(‘。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
vector<string> removeInvalidParentheses(string s) {
vector<string> res;
recursiveRomove(res, s, 0, 0, '(', ')');
return res;
}
private:
void recursiveRomove(vector<string> &resultVec, string s, int startInd, int deleteInd, char leftBracket, char rightBracket) {
int counter = 0;
for (int i = startInd; i < s.length(); i++) {
if (s[i] == leftBracket) {
counter++;
} else if (s[i] == rightBracket) {
counter--;
}
if (counter >= 0) {
continue;
}
for (int j = deleteInd; j <= i; j++) {
if (s[j] == rightBracket && (j == deleteInd || s[j - 1] != rightBracket)) {
recursiveRomove(resultVec, s.substr(0, j) + s.substr(j + 1, s.length() - j - 1), i, j, leftBracket, rightBracket);
}
}
return; //只有符合條件的字符串纔可能逆序檢查
}
string reverseStr(s.rbegin(),s.rend());
if (leftBracket == '(') {
recursiveRomove(resultVec, reverseStr, 0, 0, ')', '(');
} else {
resultVec.push_back(reverseStr);
}
}
};
int main(int argc, const char * argv[]) {
Solution s;
//")(f" s[j - 1] != rightBracket "((()" j == deleteInd
string str = "((()";
vector<string> r = s.removeInvalidParentheses(str);
for (int i = 0; i < r.size(); i++) {
cout << r[i] << endl;
}
return 0;
}