301 删除无效的括号

题目描述:
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
说明: 输入可能包含了除 ( 和 ) 以外的字符。

示例 1:
输入: “()())()”
输出: ["()()()", “(())()”]

示例 2:
输入: “(a)())()”
输出: ["(a)()()", “(a())()”]

示例 3:
输入: “)(”
输出: [""]

方法1:
参考代码
主要思路:
(1)先统计出要删除的左括号和右括号的数量;
(2)使用递归生成需要的字符串,具体看代码;
(3)为了去除重复的元素,使用unordered_set进行去重,最后将unordered_set转成vector返回;

class Solution {
public:
	//递归
    void dfs(string& s,unordered_set<string>& st,string path,int erase_l,int erase_r,int index,int diff){
        if(index==s.size()){//在索引满足要求时
            if(diff==0){//若已经加入到当前字符串的左右括号的数量满足要求,则是符合要求的字符串
                st.insert(path);
            }
            return;
        }
        //若当前字符是左括号
        if(s[index]=='('){
        	//将当前左括号加入到当前字符串中
            dfs(s,st,path+s[index],erase_l,erase_r,index+1,diff+1);
            if(erase_l>0){//若还能够删除左括号,则尝试跳过当前括号,既相当于删除当前左括号,继续递归
                dfs(s,st,path,erase_l-1,erase_r,index+1,diff);
            }
        }
        else if(s[index]==')'){//若当前字符是右括号
            if(diff>0){//若当前字符串中左括号更多,说明可以将当前的右括号加入到当前字符串中
                dfs(s,st,path+s[index],erase_l,erase_r,index+1,diff-1);
            }
            if(erase_r>0){//若还能够删除右括号,则尝试跳过右括号,既相当于删除右括号,继续递归
                dfs(s,st,path,erase_l,erase_r-1,index+1,diff);
            }
        }
        else{//若当期字符不是括号,则直接添加到当前字符串中
            dfs(s,st,path+s[index],erase_l,erase_r,index+1,diff);
        }
    }
    vector<string> removeInvalidParentheses(string s) {
    	//分别统计左右括号需要删除的数量
        int erase_l=0;
        int erase_r=0;
        for(char&ch:s){
            if(ch=='('){
                ++erase_l;//统计右括号的数量
            }
            else if(ch==')'){
                if(erase_l==0){
                    ++erase_r;//没有可匹配的左括号时,统计右括号的数量
                }
                else{
                    --erase_l;//在可以和右括号匹配时,减少左括号的数量
                }
            }
        }
        unordered_set<string> st;//用于去重字符串,并存储字符串
        dfs(s,st,"",erase_l,erase_r,0,0);
        return vector<string> (st.begin(),st.end());//返回vector
    }
};

方法2:
主要思路:
(1)该方法是对方法1的优化,既直接在生成当前字符串时避免生成重复的字符串,不再使用unordered_set进行去重;
(2)主要是通过一次找出所有的连续的重复的括号的个数,进行递归;

class Solution {
public:
    void dfs(string& s,vector<string>& res,string path,int erase_l,int erase_r,int index,int diff){
    	//终止条件,既遍历到了字符串的末尾
        if(index==s.size()){
            if(diff==0){//若条件满足,则将当前字符串压入到结果中
                res.push_back(path);
            }
            return;
        }
        if(s[index]=='('){//若当前字符是左括号
        	//找出连续的左括号的范围的右边的索引
            int k=index;
            while(k<s.size()&&s[k]=='('){
                ++k;
            }
            //先假设删除该段的所有的左括号
            erase_l-=k-index;
            //该循环中,逐渐添加左括号,直到不需要删除左括号的情形
            for(int i=k-index;i>=0;--i){
                if(erase_l>=0){//说明此时是合理的删除范围,可以递归进行判断,注意索引的起始点一直是 k
                    dfs(s,res,path,erase_l,erase_r,k,diff);
                }
                //逐渐的添加左括号
                path+='(';
                ++diff;
                ++erase_l;
            }
        }
        else if(s[index]==')'){//当前的字符是右括号
        	//找出连续的右括号范围的右边的索引
            int k=index;
            while(k<s.size()&&s[k]==')'){
                ++k;
            }
            //先假设删除该段的所有的右括号
            erase_r-=k-index;
            //该循环中,逐渐的添加右括号,直到不需要删除右括号的情形
            for(int i=k-index;i>=0;--i){
            	//若当前字符可删除,且是合理的字符串(合理是指当前字符串中左括号的数量是大于右括号的数量的),则进行递归调用
                if(diff>=0&&erase_r>=0){
                    dfs(s,res,path,erase_l,erase_r,k,diff);
                }
                //添加右括号
                path+=')';
                --diff;
                ++erase_r;
            }
        }
        else{//正常的将非括号的字符添加到字符串中
            dfs(s,res,path+s[index],erase_l,erase_r,index+1,diff);
        }
    }
    vector<string> removeInvalidParentheses(string s) {
    	//统计需要删除的左右括号的数量
        int erase_l=0;
        int erase_r=0;
        for(char&ch:s){
            if(ch=='('){
                ++erase_l;
            }
            else if(ch==')'){
                if(erase_l==0){
                    ++erase_r;
                }
                else{
                    --erase_l;
                }
            }
        }
        //直接存储字符串
        vector<string> res;
        dfs(s,res,"",erase_l,erase_r,0,0);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值