22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3 输出:[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
思路:dfs 回溯
1. 产生有效解的情况是left和right均等于n
2. 如果left < right, 说明当前字符串中右括号数多于左括号数,这是不不符合要求的,可以提前终止
3. 如果left < n, 说明还有剩余的左括号没用完,可以继续递归左括号
4. 如果right < n, 说明还有剩余的右括号没用完,还可以继续递归右括号
做加法:
1 class Solution { 2 public List<String> generateParenthesis(int n) { 3 // dfs回溯 4 List<String> res = new ArrayList<String>(); 5 if(n == 0) 6 return res; 7 dfs(res, 0, 0,n, ""); 8 return res; 9 } 10 11 public void dfs(List<String> res, int left, int right, int n, String curStr){ 12 // 如果left和right都等于n了,说明已经生产了一个解 13 if(left == n && right == n){ 14 res.add(curStr); 15 return; 16 } 17 // 剪枝,如果left < right, 说明当前字符串中右括号数多于左括号数,这是不不符合要求的,可以提前终止 18 if(left < right){ 19 return; 20 } 21 22 // 如果左括号数小于n说明还可以继续递归左括号 23 if(left < n){ 24 dfs(res, left + 1, right, n, curStr + "("); 25 } 26 27 // 如果右括号小于n,说明还可以继续递归右括号 28 if(right < n){ 29 dfs(res, left, right + 1, n, curStr + ")"); 30 } 31 } 32 }
复杂度分析
上面的程序是对left 和 right 做加法,这里写个做减法的程序:
1 class Solution { 2 public List<String> generateParenthesis(int n) { 3 // dfs回溯 4 5 List<String> res = new ArrayList<String>(); 6 if(n == 0) 7 return res; 8 dfs(res, n, n,n, ""); 9 return res; 10 } 11 12 public void dfs(List<String> res, int left, int right, int n, String curStr){ 13 // 如果left和right都等于n了,说明已经生产了一个解 14 if(left == 0 && right == 0){ 15 res.add(curStr); 16 return; 17 } 18 // 剪枝,如果left > right, 说明当前字符串中右括号数多于左括号数,这是不不符合要求的,可以提前终止 19 if(left > right){ 20 return; 21 } 22 23 // 如果左括号数大于0,说明还可以继续递归左括号 24 if(left > 0){ 25 dfs(res, left - 1, right, n, curStr + "("); 26 } 27 28 // 如果右括号大于0,说明还可以继续递归右括号 29 if(right > 0){ 30 dfs(res, left, right - 1, n, curStr + ")"); 31 } 32 } 33 }
使用标准的回溯,
上面两个程序其实是利用了String的不可变性,每个对 curStr 加上左右括号后其实对当前层次的curStr是没有影响的,相当于curStr自动回溯了,这里用StringBuilder代替String,标准的写一遍回溯,加深回溯的印象
1 class Solution { 2 public List<String> generateParenthesis(int n) { 3 // dfs回溯 4 5 List<String> res = new ArrayList<String>(); 6 if(n == 0) 7 return res; 8 StringBuilder curStr = new StringBuilder(); 9 dfs(res, n, n,n, curStr); 10 return res; 11 } 12 13 public void dfs(List<String> res, int left, int right, int n, StringBuilder curStr){ 14 // 如果left和right都等于n了,说明已经生产了一个解 15 if(left == 0 && right == 0){ 16 res.add(curStr.toString()); 17 return; 18 } 19 // 剪枝,如果left > right, 说明当前字符串中右括号数多于左括号数,这是不不符合要求的,可以提前终止 20 if(left > right){ 21 return; 22 } 23 24 // 如果左括号数大于0,说明还可以继续递归左括号 25 if(left > 0){ 26 curStr.append("("); 27 dfs(res, left - 1, right, n, curStr); 28 curStr.deleteCharAt(curStr.length() - 1); // 回溯到添加前的转态 29 } 30 31 // 如果右括号大于0,说明还可以继续递归右括号 32 if(right > 0){ 33 curStr.append(")"); 34 dfs(res, left, right - 1, n, curStr); 35 curStr.deleteCharAt(curStr.length() - 1); // 回溯到添加前的转态 36 } 37 } 38 }
思路来源:
https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/