22-括号生成

题目

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

题解一 动态规划

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String>[] dp=new ArrayList[n+1];//dp[n]表示当输入为n时,生成的有效的括号组合,创建数组时勿加<>
        //添加进的每一个元素都要是list!
        List<String> dp0=new ArrayList();
        dp0.add("");
        dp[0]=dp0;//处理边界条件
        for(int i=1;i<=n;i++){
            List<String> temp=new ArrayList<>();
            for(int m=0;m<i;m++){
                int k=i-1-m;
                List<String> str1=dp[m];//*
                List<String> str2=dp[k];//*
                for(String s1:str1){
                    for(String s2:str2){
                        temp.add("("+s1+")"+s2);//勿漏加括号
                    }
                }
            }
            dp[i]=temp;
        }
        return dp[n];
    }
}

思路:

  1. 考虑i=n-1时的情况。先确定(在最左边,则其他的所有有可能的情况为:"(" + 【i=p时所有括号的排列组合】 + “)” + 【i=q时所有括号的排列组合】

    其中 p + q = n-1,且 p q 均为非负整数。

    事实上,当上述 p 从 0 取到 n-1,q 从 n-1 取到 0 后,所有情况就遍历完了。

  2. 简单来说,在求N个括号的排列组合时,把第N种情况(也就是N个括号排列组合)视为单独拿一个括号E出来,剩下的N-1个括号分为两部分,P个括号和Q个括号,P+Q=N-1,然后这两部分分别处于括号E内和括号E的右边,各自进行括号的排列组合。由于我们是一步步计算得到N个括号的情况的,所以小于等于N-1个括号的排列组合方式我们是已知的(用合适的数据结构存储,方便后续调用,且在存储时可利用特定数据结构实现题目某些要求,如排序,去重等),且P+Q=N-1,P和Q是小于等于N-1的,所以我们能直接得到P个和Q个括号的情况,进而得到N个括号的结果!

  3. linkedlist的方法:

    add,remove,contains,get(index),

    void push(E e):与addFirst一样,实际上它就是addFirst;
    E pop():与removeFirst一样,实际上它就是removeFirst;
    E poll():查询并移除第一个元素;

    E peek():获取第一个元素,但是不移除;

    boolean offer(E e):在链表尾部插入一个元素;

    Arrays.asList("")//字符串转成list
    

题解二 深度优先+剪枝

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> res=new ArrayList<>();
        if(n==0){
            return res;
        }
        dfs("",n,n,res);
        return res;
    }
    private void dfs(String curStr,int left,int right,List<String> res){
        //递归终止的时候加入结果集
        if(left==0&&right==0){
            res.add(curStr);
            return;
        }
        //因为要先固定左括号,所以左括号可以多,右括号不能多
        if(left>right){
            return;
        }
        if(left>0){
            dfs(curStr+"(",left-1,right,res);
            //不终止dfs!
        }
        if(right>0){
            dfs(curStr+")",left,right-1,res);
        }
    }
}

思路:

  1. 当前左右括号都有大于 0个可以使用的时候,才产生分支;
    产生左分支的时候,只看当前是否还有左括号可以使用;
    产生右分支的时候,还受到左分支的限制,右边剩余可以使用的括号数量一定得在严格大于左边剩余的数量的时候,才可以产生分支;
    在左边和右边剩余的括号数都等于 0的时候结算。

  2. 固定一个(,枚举另一个)的位置。

  3. LinkedList是采用链表的方式来实现List接口的,它本身有自己特定的方法,如: addFirst(),addLast(),getFirst(),removeFirst()等. 由于是采用链表实现的,因此在进行insert和remove动作时在效率上要比ArrayList要好得多!适合用来实现Stack(堆栈)与Queue(队列),前者先进后出,后者是先进先出.

    ArrayList实现了List接口,它是以数组的方式来实现的,数组的特性是可以使用索引的方式来快速定位对象的位置,因此对于快速的随机取得对象的需求,使用ArrayList实现执行效率上会比较好.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codrab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值