LeetCode第二十二题(括号生成)

223 阅读1分钟

暴力解法(Java)

核心思想: 对于n对括号,可以生成2^2n个括号组合且每个括号组合的长度为2n,逐一判断括号组合是否有效即可。

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> resList = new ArrayList<>();//结果集
        StringBuilder sb = new StringBuilder();//用于保存生成的括号组合
        getParenthesis(sb, resList, n);//递归生成括号组合,并将有效的括号组合加入结果集
        return resList;
    }

    //递归生成括号组合,并将有效的括号组合加入结果集
    public void getParenthesis(StringBuilder sb, List<String> resList, int n){
        if(sb.length() == 2 * n && isValid(sb))//长度为2n且有效
            resList.add(sb.toString());
        if(sb.length() < 2 * n){//同一位置既可以生成左括号“(”,也可以生成右括号“)”
            sb.append('(');//生成左括号
            getParenthesis(sb, resList, n);
            sb.deleteCharAt(sb.length() - 1);
            sb.append(')');//生成右括号
            getParenthesis(sb, resList, n);
            sb.deleteCharAt(sb.length() - 1);
        }
    }

    //对生成的括号组合的有效性进行判断
    public boolean isValid(StringBuilder sb) {
        int count = 0;//count=0表示有效的括号组合
        for(int i = 0; i < sb.length(); i++){
            if(sb.charAt(i) == '(')
                count++;
            else
                count--;
            if(count < 0)//右括号多于左括号
                return false;
        }
        return count == 0;
    }
}

回溯解法(Java)

核心思想: 上述解法中,任意位置都可以生成左括号“(”或者是右括号“)”,但实际上并非如此,左括号和右括号最多有n个,并且当前的括号组合中左括号数必须小于或等于右括号数,因此,如果当前的括号组合中的左括号数leftCount小于n,则可以生成左括号;如果当前的括号组合中的右括号数rightCount小于左括号数leftCount,则可以生成右括号。

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> resList = new ArrayList<>();//结果集
        StringBuilder sb = new StringBuilder();//用于保存生成的括号组合   
        getParenthesis(sb, resList, 0, 0, n);//递归生成括号组合,并将有效的括号组合加入结果集 
        return resList;       
    }
    
    //生成括号组合,并将有效的括号组合加入结果集
    public void getParenthesis(StringBuilder sb, List<String> resList, int leftCount, int rightCount, int n){
        //如果当前的括号组合中,左括号数leftCount等于右括号数rightCount且等于n
        if(leftCount == n && rightCount == n)
            resList.add(sb.toString());
        //如果当前的括号组合中的左括号数leftCount小于n
        if(leftCount < n){
            sb.append('(');//生成左括号
            getParenthesis(sb, resList, leftCount + 1, rightCount, n);
            sb.deleteCharAt(sb.length() - 1);
        }
        //如果当前的括号组合中的右括号数rightCount小于左括号数leftCount
        if(rightCount < leftCount){
            sb.append(')');//生成右括号
            getParenthesis(sb, resList, leftCount, rightCount + 1, n);
            sb.deleteCharAt(sb.length() - 1);
        }
    }
}

动态规划

核心思想: n对括号生成的有效括号组合可以用(a)b来表示,其中a和b分别是一个有效的括号组合(可以为空),即a为p对括号生成的有效括号组合,b为q对括号生成的有效括号组合,且p+q=n-1,遍历a和b的所有可能性并拼接,即可得到n对括号生成的有效括号组合。

f(0)=""f(0)=""
f(n)="("+f(p)+")"+f(q)f(n)="("+f(p)+")"+f(q)

其中p + q = n - 1

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String>[] dp = new List[n + 1];//记录f0~fn有效括号组合,其中fn表示n对括号生成的有效括号组合
        dp[0] = Arrays.asList("");//f0=[""]
        for (int i = 1; i <= n; i++) {
            dp[i] = new ArrayList<>();//i对括号生成的有效括号组合
            for (int p = 0; p < i; p++) {//p = 0 ~ i - 1,则q = i - 1 - p
                for (String a : dp[p]) {//a为p对括号生成的有效括号组合
                    for (String b : dp[i - 1 - p]) {//b为q对括号生成的有效括号组合
                        dp[i].add("(" + a + ")" + b);//拼接a和b的所有可能性
                    }
                }
            }
        }
        return dp[n];
    }
}