22 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:

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

The Idea: Recursive build from the base case where if n = 0, then sol = { "" }, and if n = 1, then sol = { "()" }. If we continue this pattern, we will notice that every nth case can be built from n-1th case. That is, for every nth case, we insert a parenthesis pair "()" to every left parenthesis. Additionally, we insert a parenthesis pair at the beginning. To take care of duplicates, use an unordered_set. One big problem with this implementation is that we end up calculating a lot of redundent parenthesis sets.

vector<int> find_left_paren_loc(const string &s) {
    vector<int> locs;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '(')
            locs.push_back(i);
    }
    return locs;
}

vector<string> _generateParenthesis(int n, vector<string> &prev, unordered_set<string> &unique) {
    if (n > 0) {
        vector<string> next;
        for (string &s : prev) {

            vector<string> candidates;
            vector<int> left_locs = find_left_paren_loc(s);
            for (int i : left_locs) {
                string str_cp = s;
                candidates.push_back(str_cp.insert(i + 1, "()"));
            }
            candidates.push_back("()" + s);

            for (const string &s1 : candidates) {
                if (unique.find(s1) == unique.end()) {
                    next.push_back(s1);
                    unique.insert(s1);
                }
            }
        }
        return _generateParenthesis(n - 1, next, unique);
    }

    return prev;
}

vector<string> generateParenthesis(int n) {
    unordered_set<string> unique;
    vector<string> prev;

    prev.push_back("");
    return _generateParenthesis(n, prev, unique);
}


int main() 
{
    for (int i : {0, 1, 2, 3, 4, 5, 6}) {
        print(generateParenthesis(i));
        cout << endl;
    }
}

Solution 2 with optimal time complexity:

class Solution:
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """

        solutions = []
        def __generateParenthesis(cur, left, right):
            if left == 0 and right == 0:
                solutions.append(cur)
            else:
                if right:
                    __generateParenthesis(cur + ')', left, right - 1)
                if left:
                    __generateParenthesis(cur + '(', left - 1, right + 1)

        __generateParenthesis('', n, 0)
        return solutions


obj = Solution()
print(obj.generateParenthesis(4))

Last updated