Leetcode 22. 括号生成

题目

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

例如,给出 n = 3,生成结果为:

[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]

解答

解法一:回溯法

思路是:通过记录剩下能放的左/右括号数量,来生成合法的序列。

保证递归时条件:

  1. 左括号的数量 小于 总次数 n ,才有可能添加左括号。
  2. 右括号的数量 小于 左括号的数量,才有可能添加右括号。

时刻保证上述两个条件,就能保证最后得到的字符串是合法的。

代码一
class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> res = new ArrayList<>();
        backtrace(res, "", 0, 0, n);
        return res;
    }
    
    
    private void backtrace(List<String> res, String cur, int open, int close, int max) {
        if(cur.length() == max * 2) {
            res.add(cur);
            return;
        }
        
        if(open < max) backtrace(res, cur + "(", open + 1, close, max);
        if(close < open) backtrace(res, cur + ")", open, close + 1, max);
    }
}
结果

在这里插入图片描述
代码还可以再次优化,使用 char[ ] 减少大量的字符串拼接。

优化后代码
class Solution {
    
    List<String> res = new ArrayList<>();
    public List<String> generateParenthesis(int n) {
        char[] cur = new char[2 * n];
        backtrace(cur, 0, 0, 0, n);
        return res;
    }
    
    
    private void backtrace(char[] cur, int index, int open, int close, int max) {
        if(open == close && open == max) {
            res.add(new String(cur));
            return;
        }
        
        if(open < max) {
            cur[index] = '(';
            backtrace(cur, index + 1, open + 1, close, max);
        }
        
        if(close < open) {
            cur[index] = ')';
            backtrace(cur, index + 1, open, close + 1, max);
        }
    }
}
结果

在这里插入图片描述

解法二:动态规划

每一个 c 的位置,都可以确定一部分结果集。

假如有 n 对括号,那么所有匹配的括号只可能在 0 - c 之间或者 0 - c 之外 。

而除了位置 0 和位置 c 组成的括号外,其他部分的括号加起来正好是: a + (n - a - 1) = n - 1 对

这样就可以产生一部分的结果集:【 ( a对的结果集 ) n - a -1 对括号的结果集 】。

对 c 进行迭代,就会得到所有正确匹配括号的结果集了。

在这里插入图片描述

代码一:备忘录
class Solution {
    
    Map<Integer, List<String>> memo = new HashMap<>();
    public List<String> generateParenthesis(int n) {
        if(memo.containsKey(n)) return memo.get(n);
        
        List<String> ans = new ArrayList();
        if (n == 0) {
            ans.add("");
        } else {
            for (int c = 0; c < n; ++ c)
                for (String left: generateParenthesis(c))
                    for (String right: generateParenthesis(n - 1 - c))
                        ans.add("(" + left + ")" + right);
        }
        
        memo.put(n, ans);
        
        return ans;
    }
}
代码二:自底向上的动态规化
class Solution {
    public List<String> generateParenthesis(int n) {
        Map<Integer, List<String>> dp = new HashMap<>();
        dp.put(0, new ArrayList<>(Arrays.asList("")));
        
        for(int i = 1; i <= n; i ++) {
            List<String> cur = new ArrayList<>();
            for(int c = 0; c < i; c ++) {
               for(String left : dp.get(c)) {
                   for(String right : dp.get(i - c - 1)) {
                       cur.add("(" + left + ")" + right);
                   }
               }
            }
            
            dp.put(i, cur);
        }
        
        return dp.get(n);
    }
}
结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值