題目描述:c++
數字 n 表明生成括號的對數,請你設計一個函數,用於可以生成全部可能的而且 有效的 括號組合。函數
方法一: 回溯 + 剪枝 spa
將 生成 n 對 有效括號的過程就是在一棵剪枝了的二叉樹上遍歷的過程。下圖是 n = 3 的狀況。設計
從上面的圖片中咱們能夠很明顯的看到,最後五條畫黑線的葉節點就是最終的結果,其中左分支都是添加左括號,code
右分支都是添加右括號。blog
添加左(右)括號的條件是 當前還有 左(右)括號能夠用,特別地,添加右括號還須要當前 已經添加的右括號的數量圖片
不能比已經添加的左括號的多。由於 合法的括號序列的第一個必定是左括號,此時右括號數量要是比左括號多,那必定有右括號數學
尚未左括號配對。string
因此,剪枝條件 就是 if (l > n || r > n || r > l) { return } 。l ,r 分別表示當前狀態下,序列中 左右括號的數量。初始化爲 0;io
如上圖,遍歷到黑線葉節點,即獲得 了一個合法的 括號序列,須要將獲得的合法序列 放到結果集中。
代碼以下:
class Solution { public: vector<string> generateParenthesis(int n) { N = n; res.clear(); dfs("",0,0); return res; } void dfs(string str,int l,int r) { if(l > N || r > N || r > l) { return; } if(l == N && r == N) { res.push_back(str); return; } dfs(str + '(', l + 1, r); dfs(str + ')', l, r + 1); return; } private: vector<string> res; int N; };
方法二: 動態規劃
分析:動態規劃的問題可使用相似於數學概括法的思想來分析,假設咱們已經知道了 0,1,2,... ,n-1 對括號的全部的合法括號序列,
如今 求 有 n 對括號的全部的合法序列。對 一個 有 n 對 括號的 合法括號序列,必定是 '(' 開頭的 。
合法括號序列的 形式爲 "(" + in_str +")" + out_str ,且 in_str 和 out_str 都是合法的括號序列串或空串。
假設 "(" + in_str +")" + out_str 是一個有n 對 括號的 合法括號序列,假設 in_str 有 n1 對括號,out_str 有n2 對括號。
n 1 和 n2 之間必須知足:
0 <= n1 <= n-1 , 0 <= n2 <= n-1 , n1 + n2 = n - 1
假設 n = 3 ,則有
n1 n2
0 2
1 1
2 0
因此,求 有n 對 括號的全部的合法括號序列,即求上面 n_str 和 out_str 的全部組合狀況。
另 vector<vector<string> > dp(n+1); dp[i] 表示 有i 對 括號的 全部合法序列,設 0<= j <= i-1 ,則 in_str 是 dp[ j ]中的一個序列,
同時 out_str 是 dp[i-1 -j] 中的一個序列。
c++ 代碼以下:
1 class Solution { 2 public: 3 vector<string> generateParenthesis(int n) { 4 vector<vector<string> > dp(n+1); 5 if( n <= 0) return {}; 6 //base case 7 dp[0] = {""}; 8 dp[1] = {"()"}; 9 //dp status move 10 for(int i = 2; i <= n;++i) 11 { 12 for(int j = 0;j <= i-1 ; ++j) 13 { 14 for(string &in_str:dp[j]) 15 for(string &out_str:dp[i-1-j]) 16 { 17 string str_tmp = "(" + in_str + ")" + out_str; 18 dp[i].push_back(str_tmp); 19 } 20 } 21 } 22 return dp[n]; 23 } 24 };