Thursday, August 3, 2017

Generate Parentheses

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:

[ "((()))", "(()())", "(())()", "()(())", "()()()" ]

class Solution { public: vector<string> generateParenthesis(int n) { vector<string> sol; if (n < 1) { return sol; } sol.push_back("()"); for (int i = 2; i <= n; i++) { int size = sol.size(); for (int j = 0; j < size; j++) { string paren = sol[j]; int one_paren_size = paren.size(); for (int k = 0; k <= one_paren_size/2; k++) { string new_paren = paren; new_paren.insert(k, "()"); if (find(sol.begin(), sol.end(), new_paren) == sol.end()) { sol.push_back(new_paren); } } } sol.erase(sol.begin(), sol.begin() + size); } return sol; } };

====== Another one =========
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
    void gp(string str,int l,int r, int &n, vector<string> &res){
        if (l>n){return;}
        if (l==n && r==n){
            res.push_back(str);
        }else{
            gp(str+"(",l+1,r,n,res);
            if (l>r){
                gp(str+")",l,r+1,n,res);
            }
        }
    }
    vector<string> generateParenthesis(int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<string> res;
        if (n==0){return res;}
        gp("",0,0,n,res);
        return res;
    }
};






Approach 2: Backtracking

Intuition and Algorithm
Instead of adding '(' or ')' every time as in Approach 1, let's only add them when we know it will remain a valid sequence. We can do this by keeping track of the number of opening and closing brackets we have placed so far.
We can start an opening bracket if we still have one (of n) left to place. And we can start a closing bracket if it would not exceed the number of opening brackets.
Complexity Analysis
Our complexity analysis rests on understanding how many elements there are in generateParenthesis(n). This analysis is outside the scope of this article, but it turns out this is the n-th Catalan number \dfrac{1}{n+1}\binom{2n}{n}, which is bounded asymptotically by \dfrac{4^n}{n\sqrt{n}}.
  • Time Complexity : O(\dfrac{4^n}{\sqrt{n}}). Each valid sequence has at most n steps during the backtracking procedure.
  • Space Complexity : O(\dfrac{4^n}{\sqrt{n}}), as described above, and using O(n) space to store the sequence. 

Approach 3: Closure Number

Intuition
To enumerate something, generally we would like to express it as a sum of disjoint subsets that are easier to count.
Consider the closure number of a valid parentheses sequence S: the least index >= 0 so that S[0], S[1], ..., S[2*index+1] is valid. Clearly, every parentheses sequence has a unique closure number. We can try to enumerate them individually.
Algorithm
For each closure number c, we know the starting and ending brackets must be at index 0and 2*c + 1. Then, the 2*c elements between must be a valid sequence, plus the rest of the elements must be a valid sequence.
Complexity Analysis
  • Time and Space Complexity : O(\dfrac{4^n}{\sqrt{n}}). The analysis is similar to Approach 2.

No comments:

Post a Comment