22.Generate Parentheses&n對括號的全部有效組合
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
"((()))", "(()())", "(())()", "()(())", "()()()"
我們最初的想法可能是採用一種遞迴的方式,也就是通過新增成對的括號,從f(n-1)構建f(n)的解。這是很好的一種直覺。
讓我們來考慮n=3時候的解:
我們如何從n=2的解構造得到上面的解呢?
我們可以在每一對已經存在的括號中間插入一對括號,也可以在字串的開頭插入一對括號。任何其他我們可以插入括號的地方,例如在字串的結尾,都可以歸納為前面的情況。
所以,我們可以得到:
但是等等,我們得到的列表中存在重複的字串,出現了兩次。
如果我們要使用這個方法,在將一個字串加入我們的列表之前,需要進行重複檢查。
class Solution { public: vector<string> generateParenthesis(int n) { set<string> retSet; if(n == 0) { retSet.insert(""); } else { vector<string> prev = generateParenthesis(n-1); for(vector<string>::iterator it = prev.begin();it != prev.end();++it) { string str = *it; for(int i = 0;i<str.length();++i) { if(str[i] == '(') { string s = insertInside(str,i); retSet.insert(s); } } retSet.insert("()"+str); } } vector<string> retVec(retSet.begin(),retSet.end()); return retVec; } string insertInside(const string& str,int leftIndex) { string left = str.substr(0,leftIndex+1); string right = str.substr(leftIndex+1); return left+"()"+right; } };
這個方法可以工作,但它不是非常高效。我們浪費了很多時間來處理重複的字串。
我們可以通過從零開始構建字串,來避免重複字串。在這個方法中,我們新增左右括號,只要我們的表示式是合法的。
每次遞迴呼叫,我們有字串中一個特定字元的索引。我們需要選擇一個左括號或者右括號。那麼何時可以用左括號,何時可以用右括號?
(1)左括號:只要左括號還沒用完,就可以插入左括號。
(2)右括號:只要不造成語法錯誤,就可以插入右括號。何時會出現語法錯誤?如果右括號比左括號還多,就會出現語法錯誤。
所以,我們只需要記錄允許插入的左右括號數目。如果還有左括號可以用, 就插入一個左括號,然後遞迴。如果餘下的右括號比左括號多(使用中的左括號比右括號還多),就插入一個右括號然後遞迴。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> result;
if(n == 0)
return result;
string s = "";
Helper(result,s,n,0);
return result;
}
/* this hepler function insert result strings to "vector<string> result"
When number of '(' less than "n", can append '(';
When number of '(' is more than number of ')', can append ')';
string cur : current string;
int left : number of '(' that have not put into "string s";
int right : number of '(' minus number of ')' in the "string s";
*/
void Helper(vector<string>& result, string cur, int left, int right)
{
if(!left && !right)
{
result.push_back(cur);
return;
}
if(right > 0)
Helper(result,cur+')',left,right-1);
if(left > 0)
Helper(result,cur+'(',left - 1,right+1);
}
};