301. 删除无效的括号

Q:

删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。

说明: 输入可能包含了除 ( 和 ) 以外的字符。

示例 1:

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

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

输入: “)(”
输出: [""]

A:

这题最主要是一开始要算出要删除的左括号和右括号的数量,以此作为目标去进行递归,不然情况是2的n次方。
dfs或bfs都可以,但由于对每次字符串的遍历中要保存剩余要删除的左右括号数量,dfs会显得方便一些,因为可以直接加在函数参数里。而bfs加参数不好加,要么定义个struct,或者多个queue同时push、pop。
注意有两个地方剪枝,大大减少了运算量。
1: 当前dfs函数遍历的字符串为s1,在索引i位置删除一个括号后得到s2,在dfs(s2)函数中从i开始遍历就可以了,前面的元素都已经在父函数dfs(s1)中遍历过了。
2: 当前遍历到i,若s[i-1]==s[i],则不必删除s[i]进入子层dfs,因为删除s[i]和删除s[i-1]得到的字符串是一样的。在前一个删除s[i-1]的dfs函数中考察过了,故可以直接跳过。但一定注意,当前遍历到i若有s[i]==s[i+1],不能向刚才那样跳过。这样如果有连续(((((这样的串,会连续跳到结尾而没有考察任何一个!之前可以跳是建立在已经考察过相同情况的子串的前提之下的!

class Solution {
public:
    bool check(const string& s)
    {
        int cnt=0,siz=s.size();
        for(int i=0;i<siz;++i)
        {
            if(s[i]!='(' and s[i]!=')')
            {
                continue;
            }
            if(s[i]=='(')
            {
                ++cnt;
            }
            if(s[i]==')')
            {   
                if(cnt>0)
                {
                    --cnt;
                }
                else
                {
                    return false;
                }
            }
        }
        return cnt==0;
    }
    vector<string> removeInvalidParentheses(string s) 
    {
        int le=0,ri=0;
        vector<string> res;
        for(int i=0;i<s.length();++i)
        {
            if(s[i]=='(')
            {
                ++le;
            }
            if(s[i]==')')
            {
                if(le>0)
                {
                    --le;   //前面有左括号则配对
                }
                else
                {
                    ++ri;   //否则右括号多一个
                }
            }
        }
        //DFS
        set<string> myset;
        dfs(s,le,ri,0,myset);
        for(auto x:myset)
        {
            res.push_back(x);
        }
        return res;
    }
    void dfs(string s,int left,int right,int limit,set<string>& res)
    {
        // cout<<s<<" "<<left<<" "<<right<<endl;
        if(left==0 and right==0)
        {
            if(check(s))
            {
                res.insert(s);
            }
            return;
        }
        for(int i=limit;i<s.length();++i)   //从limit开始遍历,省略不必要的遍历
        {
            if(i>limit and s[i]==s[i-1])
            {
                continue;
            }
            if(s[i]=='(' and left>0)
            {
                dfs(s.substr(0,i)+s.substr(i+1),left-1,right,i,res);
            }
            if(s[i]==')' and right>0)
            {
                dfs(s.substr(0,i)+s.substr(i+1),left,right-1,i,res);
            }
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值