LeetCodes刷题总结2——括号生成

题目

https://leetcode-cn.com/problems/generate-parentheses/

思路1——dfs

本题在暴力破解(列出所有情况)的基础上很容易想到回溯和剪枝,由于涉及到递归,有些难度。先上一个其他大神给的深度优先遍历的模板:

void dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
 
    }  
}  

实际上这也是递归的模板。利用这个思路不断尝试添加左括号和右括号可以得到剪枝条件。

剪枝对于新手来言确实有难度,一个好的方法就是自己举一个简单例子慢慢试,比如假设有两个左括号和两个右括号,按照下图尝试得到剪枝条件。

根据以上思路可以得到代码:

class Solution {
public:
    vector<string> res;
    void dfs(string parenthesis,int left,int right){ 
        //参数:当前字符串,左括号剩余数量,右括号剩余数量
        if(left==0&&right==0){ //递归结束
            res.push_back(parenthesis);
            return;
        }
        if(left>0){ //满足剪枝条件1-尝试加入(
            dfs(parenthesis+'(',left-1,right);
        }
        if(right>left){ //满足剪枝条件2-尝试加入)
            dfs(parenthesis+')',left,right-1);
        }
        
    }
    vector<string> generateParenthesis(int n) {
        string parenthesis="";
        dfs(parenthesis,n,n);
        return res;
    }
};

 代码很简单,值得一提的是dfs(parenthesis+'(',left-1,right);这一句是下面三句的简化版:

parenthesis.push_back('(');
dfs(parenthesis,left-1,right);
parenthesis.pop_back();

前者比较高明,将需要回溯的值加入到参数,值得学习。

思路2——dp

动态规划的思路确实难想,不过一道题有多种解法都研究透了才能举一反三。动态规划的做法像数学归纳法。对本题已知n-1对括号的排列组合情况,求n对时的情况。就是在n-1对括号排列好的情况下,怎么加入一对括号。

对本题除了n=0的情况,无论什么排列第一个括号肯定是'(',所以这个就是第n对括号的左括号放置位置(这个很难想),那么右括号就是向右不断遍历,这样得到的情况就是dp[n]。

附上代码大家好好思考:

//dp做法
//已知n-1对括号的排列组合情况,求第n对情况
class Solution{
public:
    vector<string> generateParenthesis(int n){
        if(n==0) return {};
        if(n==1) return {"()"};
        vector<vector<string>> dp(n+1);
        dp[0]={""};
        dp[1]={"()"};
        for(int i=2;i<=n;i++){ //从n至少为2开始
            for(int j=0;j<i;j++){
                for(string p:dp[j]){
                    for(string q:dp[i-j-1]){
                        string temp="("+p+")"+q; //左括号一定在最左边
                        dp[i].push_back(temp);
                    }
                }
            }
        }
        return dp[n];
    }
};
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值