leetcode 困难 —— 删除无效的括号(超详细思路)

(特别简单的一道题,没有难度,可能考验的就是编程能力,能不能短时间敲完代码,我是菜狗)

题目:
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。

题解:
首先看一眼数据范围 s 中至多含 20 个括号,一看到这个 20,瞬间我就直接无脑用二进制枚举所有状态,然后写到最后,发现不对,因为要去重,去重前要排序,可能会超时

但当时想着可能要经过 ”是否是有效字符串“ 和 ”是否是最长字符串“,感觉经过两次筛选,应该不会超时
(我现在都没想到什么样例能让他超时,但是确实超了)

代码如下:

class Solution {
public:
    bool test(string s) {
        int flag = 0;
        for(int i = 0; i < s.size(); i++) {
            if(s[i] == '(') flag++;
            else if(s[i] == ')' && flag != 0) flag--;
            else if(s[i] == ')' && flag == 0) return false;
        }
        if(flag == 0) return true;
        else return false;
    }
    vector<pair<int, string> > ddd;
    vector<string> res;
    vector<string> removeInvalidParentheses(string s) {
        vector<pair<bool, int> > flag;
        for(int i = 0; i < s.size(); i++) {
            if(s[i] == '(') flag.push_back(make_pair(true, i));
            if(s[i] == ')') flag.push_back(make_pair(false, i));
        }
        for(int i = 0; i < (1 << flag.size()); i++) {
            int f = 0;
            string temp = "";
            for(int j = 0; j < flag.size(); j++) {
                while(f < flag[j].second) {
                    temp = temp + s[f];
                    f++;
                }
                f++;
                if(((i >> j) & 1) != 1) continue;
                if(flag[j].first) temp = temp + '(';
                else temp = temp + ')';
            }
            while(f < s.size()) {
                temp = temp + s[f];
                f++;
            }
            if(test(temp)) ddd.push_back(make_pair(temp.size(), temp));
        }
        int f = 0;
        for(int i = 0; i < ddd.size(); i++) {
            f = max(f, ddd[i].first);
        }
        for(int i = 0; i < ddd.size(); i++) {
            if(ddd[i].first == f) {
                res.push_back(ddd[i].second);
            }
        }
        sort(res.begin(), res.end());
        res.erase(unique(res.begin(), res.end()), res.end());
        return res;
    }
};

然后就没办法呗,只能避免去重,因为假如 ”(((((“,我们从中去除两个,只得到一种情况 “(((”,而二进制枚举的话一堆情况,难免要去重,因此我们进行 dfs,把一起出现的相同括号看成一组,比如 “(((((”,看成一种,递归的时候,只考虑 6 次,“”,“(”,… ,“(((((”,这样就不需要去重了,就可以过了

class Solution {
public:
    bool test(string s) {
        int flag = 0;
        for(int i = 0; i < s.size(); i++) {
            if(s[i] == '(') flag++;
            else if(s[i] == ')' && flag != 0) flag--;
            else if(s[i] == ')' && flag == 0) return false;
        }
        if(flag == 0) return true;
        else return false;
    }
    vector<pair<bool, int> > flag; // 记录连续的 '(' 或 ')' 出现的次数
    string str; // 把字符串 s 存入全局变量
    vector<string> solve(int a, int v, int p) {
        vector<string> res;
        string t = "";
        for(int i = 0; i < v; i++) {
            if(flag[a].first) t = t + '(';
            else t = t + ')';
        }
        p = p + flag[a].second;
        while(p < str.size() && str[p] != '(' && str[p] != ')') {
            t = t + str[p];
            p++;
        }
        if(a == flag.size() - 1) {
            res.push_back(t);
            return res;
        }
        vector<string> temp;
        for(int i = 0; i <= flag[a + 1].second; i++) {
            temp = solve(a + 1, i, p);
            for(int j = 0; j < temp.size(); j++) {
                res.push_back(t + temp[j]);
            }
        }
        return res;
    }
    vector<string> removeInvalidParentheses(string s) {
        vector<string> res;
        vector<string> ddd;
        str = s;
        int p = 0;
        while(p < s.size()) {
            int f = 0;
            if(p < s.size() && s[p] == '(') {
                while(p < s.size() && s[p] == '(') {
                    p++;
                    f++;
                }
                flag.push_back(make_pair(true, f));
            }
            f = 0;
            if(p < s.size() && s[p] == ')') {
                while(p < s.size() && s[p] == ')') {
                    p++;
                    f++;
                }
                flag.push_back(make_pair(false, f));
            }
            while(p < s.size() && s[p] != '(' && s[p] != ')') {
                p++;
            }
        }
        if(flag.size() == 0) {
            res.push_back(s);
            return res;
        }
        vector<string> temp;
        string t = "";
        p = 0;
        while(p < str.size() && str[p] != '(' && str[p] != ')') {
            t = t + str[p];
            p++;
        }
        for(int i = 0; i <= flag[0].second; i++) { // 遍历每组括号可以存在的括号数量
            temp = solve(0, i, p);
            for(int j = 0; j < temp.size(); j++) {
                if(test(temp[j])) ddd.push_back(t + temp[j]);
            }
        }
        int f = 0;
        for(int i = 0; i < ddd.size(); i++) {
        	// 注意字符串的 size() 得到的不是 int 类型,需要强转
            f = max(int(ddd[i].size()), f);
        }
        for(int i = 0; i < ddd.size(); i++) {
            if(ddd[i].size() == f) {
                res.push_back(ddd[i]);
            }
        }
        return res;
    }
};

但是呢,这样时间复杂度还是不是最优的,我们可以进行剪枝,因为实际上,我们是已知我们需要去掉几个括号的(对原始字符串遍历一遍),所以可以 dfs 多传一个参数,用作限制去掉的括号总数,为 0 就停止遍历,这样就可以优化,代码懒得写了

猜你喜欢

转载自blog.csdn.net/m0_52212261/article/details/128887441
今日推荐