1. 程式人生 > >22.Generate Parentheses&n對括號的全部有效組合

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);
    }
};