括号生成(leetcode22)
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
解析:
方法一:暴力破解
递归
为了生成所有序列,我们可以使用递归。长度为 n
的序列就是在长度为 n-1
的序列前加一个 '('
或 ')'
。
为了检查序列是否有效,我们遍历这个序列,并使用一个变量 balance 表示左括号的数量减去右括号的数量。如果在遍历过程中 balance 的值小于零,或者结束时 balance 的值不为零,那么该序列就是无效的,否则它是有效的。
/** * 暴力破解:递归 * * * */ public class leetcode22 { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); int n = in.nextInt(); System.out.println(generateParenthesis(n)); } public static List<String> generateParenthesis(int n) { List<String> result = new ArrayList<String>(); generateAll(new char[2*n],0,result); return result; } public static void generateAll(char[] current,int pos,List<String> list){ if(current.length==pos){ if(valid(current)){ list.add(new String(current)); return; } }else{ current[pos] = '('; generateAll(current,pos+1,list); current[pos]=')'; generateAll(current,pos+1,list); } } //如果balance小于0,则直接返回false,如果最后balance不等于0,也返回false private static boolean valid(char[] current) { int balance = 0; for(char ch:current){ if(ch=='('){ balance++; }else{ balance--; } if(balance<0){ return false; } } return balance==0; } }
方法二:回溯
方法一还有改进的余地:我们可以只在序列仍然保持有效时才添加 '(' or ')',而不是像 方法一 那样每次添加。
我们可以通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,
如果左括号数量不大于 n,我们可以放一个左括号。如果右括号数量小于左括号的数量,我们可以放一个右括号。
如下
public List<String> generateParenthesis(int n) { List<String> ans = new ArrayList<String>(); backtrack(ans, new StringBuilder(), 0, 0, n); return ans; } public void backtrack(List<String> ans, StringBuilder cur, int open, int close, int max) { if (cur.length() == max * 2) { ans.add(cur.toString()); return; } if (open < max) { cur.append('('); backtrack(ans, cur, open + 1, close, max); cur.deleteCharAt(cur.length() - 1); } if (close < open) { cur.append(')'); backtrack(ans, cur, open, close + 1, max); cur.deleteCharAt(cur.length() - 1); } }
/** * 回溯 * * */ public class leetcode22_1 { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); int n = in.nextInt(); System.out.println(generateParenthesis(n)); } public static List<String> generateParenthesis(int n){ List<String> result = new ArrayList<String>(); generateAll(result,new StringBuilder(),0,0,n); return result; } //回溯方法 private static void generateAll(List<String> list,StringBuilder current, int open, int close, int max) { if(current.length()==max*2){//如果current的长度等于max*2,就可以把字符串加到结果集合了 list.add(current.toString()); } if(open<close){//如果open<close,即左括号的数量小于右括号的数量,则是无效的字符串 return; } if(open<max){//如果左括号的数量还小于max,则可继续在字符串后面加( current.append("("); generateAll(list,current,open+1,close,max); current.deleteCharAt(current.length()-1); } if(close<max){//如果右括号的数量还小于max,则可继续在字符串后面加) current.append(")"); generateAll(list,current,open,close+1,max); current.deleteCharAt(current.length()-1); } } }