题目:
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:
"((()))", "(()())", "(())()", "()(())", "()()()"
思路:
所有组合的个数C是一个卡特兰数。
用更小的C去求解组合的所有可能性。我们来看下具体如何解决。一般采用递归的方法,这样可以归结为子问题去解决。在每个递归函数中记录左括号的数量和可以加入的右括号的数量,然后每次都有两种选择,一个是放入左括号,一个是放入右括号。不过这些是有附加条件的,左括号的数量要大于0,可以加入的右括号的数量也要大于0(保证结果是合法的)。递归结束条件是,左右括号数量都为0。
Attention:
1. 设计巧妙,要保证结果的合法性,必须保证左括号的数量>0 (添加左括号);采用可被添加的右括号数量(左括号数量>右括号数量)
<span style="font-size:14px;">//根据剩余左括号的数量,以及可以添加的右括号的数量,来遍历所有的可能, 只要两者不为零,都会进行两次选择(遍历两个分叉) if(m > 0) { generateParenthesis_helper(ret, str + ")", n, m-1); } if(n > 0) { generateParenthesis_helper(ret, str + "(", n-1, m+1); }</span>2. 这道题准确来讲,不涉及回溯的问题,我们只是遍历一个合法的二叉树(符合括号构成原则),并且打印所有的结果。所以不需要pop_back()添加进去的结果。因为我们是带着条件去go_deeper的,并且合法情况下,总是有两个选择。
可以试着画一个n = 2的遍历结果来加深理解。
复杂度:O(结果的数量)。
AC Code:
<span style="font-size:14px;">class Solution { public: vector<string> generateParenthesis(int n) { vector<string> ret; if(n <= 0) return ret; generateParenthesis_helper(ret, "", n, 0); return ret; } private: void generateParenthesis_helper(vector<string>& ret, string str, int n, int m) { if(n == 0 && m == 0) { ret.push_back(str); return; } //根据剩余左括号的数量,以及可以添加的右括号的数量,来遍历所有的可能, 只要两者不为零,都会进行两次选择(遍历两个分叉) if(m > 0) { generateParenthesis_helper(ret, str + ")", n, m-1); } if(n > 0) { generateParenthesis_helper(ret, str + "(", n-1, m+1); } } };</span>