力扣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;
    }
};
相关推荐
郝学胜-神的一滴3 分钟前
中秋特别篇:使用QtOpenGL和着色器绘制星空与满月
开发语言·c++·算法·软件工程·着色器·中秋
qiuiuiu41321 分钟前
CPrimer Plus第十六章C预处理器和C库总结2-qsort函数
java·c语言·算法
JuneXcy1 小时前
C++知识点总结用于打算法
c++·算法·图论
wdfk_prog3 小时前
[Linux]学习笔记系列 -- lib/timerqueue.c Timer Queue Management 高精度定时器的有序数据结构
linux·c语言·数据结构·笔记·单片机·学习·安全
zhuzhuxia⌓‿⌓3 小时前
线性表的顺序和链式存储
数据结构·c++·算法
未知陨落3 小时前
LeetCode:95.编辑距离
算法·leetcode
杨小码不BUG3 小时前
小鱼的数字游戏:C++实现与算法分析(洛谷P1427)
c++·算法·数组·信奥赛·csp-j/s
高山有多高3 小时前
栈:“后进先出” 的艺术,撑起程序世界的底层骨架
c语言·开发语言·数据结构·c++·算法
YouEmbedded4 小时前
解码查找算法与哈希表
数据结构·算法·二分查找·散列表·散列查找·线性查找