力扣301:删除无效的括号

力扣301:删除无效的括号

题目

给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。

返回所有可能的结果。答案可以按 任意顺序 返回。

思路

看到任意顺序所以先想回溯。

想到回溯先想回溯的结束条件是什么:字符串是否是有效的也就是字符串里的括号能否全部匹配成功。所以我们需要设计一个返回值为bool类型的函数判断字符串是否有效,具体实现也好想既然是判断括号是否能否匹配上我们只需要定义一个整型total,遇到左括号就++遇到右括号就--,然后再判断total是否小于0如果小于就说明右括号的数量大于左括号了直接返回false。等循环结束后再判断total是否为0为0就返回true不为零就返回false。

回溯的结束条件讲完了接下来就是如何进行回溯,我们先仔细观察题目。题目上说要删除最小的无效括号所以我们没法随意的删除我们必须先计算出要删除多少个左括号和右括号才能在数量上匹配也就是左括号和右括号的数量是相同的。怎么计算呢?我们定义两个遍历一个左括号的数量leftcount一个右括号的数量rightcount,然后我们遍历字符串遇到左括号就对leftcount++,遇到右括号的时候我们先判断左括号的数量leftcount是否大于零如果大于零说明这一对括号可以匹配上所以要对leftcount进行--。如果小于0说明这个右括号是多余的也就要对rightcount进行++。在一轮遍历后我们就得到了要删除的左括号和右括号数量。在得到了要删除的左括号和右括号的数量后我们就可以开始回溯了,回溯的本体也很简单只要遇到左括号并且leftcount大于0我们就尝试删除左括号,右括号同理。

在回溯的大概流程讲完后就是其中的一些特殊情况,第一回溯结束的判断条件不止是字符串是否有效还有一个条件就是剩下的字符串数量要大于要删除的括号数量也就是leftcount+rightcount。这个道理很简单剩下的字符串全删了都没法完成左右括号数量上的匹配那就可以直接不用玩了。还有一个细节是剪枝方面的,我们要返回的是所以可能的结果所以可能有重复的情况出现,那么什么情况下会有重复呢?多个相同的括号堆在一起也就是连续好几个左括号或者右括号所以我们就需要进行剪枝也就是判断当前位置的符号是否和上一个位置的符号相同,如果相同就直接下一轮。这样就避免了重复答案的出现。

代码

cpp 复制代码
class Solution {
public:
    vector<string> res;
    bool IsVaild(string tmp) {
        int total = 0;
        for (auto ch : tmp) {
            if (ch == '(') {
                total++;
            } else if (ch == ')') {
                total--;
            }
            if (total < 0) {
                return false;
            }
        }
        return total == 0;
    }
    void dfs(string s, int start, int leftcount, int rightcount) {
        // 回溯的结束条件:字符串是否是有效的
        if (IsVaild(s)) {
            res.push_back(s);
            return;
        }
        for (int i = start; i < s.size(); i++) {
            // 如果要删除的字符串数量已经大于剩下的字符数就直接返回
            if (leftcount + rightcount > s.size() - i) {
                return;
            }
            // 进行剪枝:去除那些连续的括号避免生成重复的字符串
            if (i != start && s[i] == s[i - 1]) {
                continue;
            }
            // 去除一个左括号
            if (leftcount > 0 && s[i] == '(') {
                dfs(s.substr(0, i) + s.substr(i + 1), i, leftcount - 1,
                    rightcount);
            }
            // 去除一个右括号
            if (rightcount > 0 && s[i] == ')') {
                dfs(s.substr(0, i) + s.substr(i + 1), i, leftcount,
                    rightcount - 1);
            }
        }
    }
    vector<string> removeInvalidParentheses(string s) {
        // 需要删除的左括号和右括号数量
        int leftcount = 0;
        int rightcount = 0;
        // 先计算出需要删减出多少个括号
        // 才能在数量上完成匹配
        for (auto ch : s) {
            if (ch == '(') {
                leftcount++;
            } else if (ch == ')') {
                // 如果还有左括号那么这两个括号就可以进行匹配也就不用删除了
                if (leftcount > 0) {
                    leftcount--;
                } else {
                    rightcount++;
                }
            }
        }
        // 然后通过回溯来完成删除工作
        dfs(s, 0, leftcount, rightcount);
        return res;
    }
};
相关推荐
muyun28001 小时前
History 模式 vs Hash 模式:Vue Router 技术决策因素详解
vue.js·算法·哈希算法
打马诗人2 小时前
【YOLO11】【DeepSort】【NCNN】使用YOLOv11和DeepSort进行行人目标跟踪。(基于ncnn框架,c++实现)
人工智能·算法·目标检测
瓦香钵钵鸡3 小时前
机器学习通关秘籍|Day 02:特征降维、用KNN算法和朴素贝叶斯实现分类
算法·机器学习·分类·贝叶斯·knn·超参数搜索·交叉验证
czhc11400756634 小时前
linux81 shell通配符:[list],‘‘ ``““
数据结构·chrome·list
山烛6 小时前
决策树学习全解析:从理论到实战
人工智能·python·学习·算法·决策树·机器学习
修己xj6 小时前
探索设计模式的宝库:Java-Design-Patterns
算法
鲨鱼辣椒_TUT6 小时前
MySQL连接算法和小表驱动大表的原理
mysql·算法·adb
设计师小聂!7 小时前
力扣热题100------21.合并两个有序链表
算法·leetcode·链表
এ᭄画画的北北7 小时前
力扣-1.两数之和
数据结构·算法·leetcode