zoukankan      html  css  js  c++  java
  • Remove-Invalid-Parentheses-题解

    题意

    Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

    Note: The input string may contain letters other than the parentheses ( and ).

    Examples:
    "()())()" -> ["()()()", "(())()"]
    "(a)())()" -> ["(a)()()", "(a())()"]
    ")(" -> [""]
    Credits:
    Special thanks to @hpplayer for adding this problem and creating all test cases.

    Subscribe to see which companies asked this question

    思路

    无论是BFS还是DFS,其都是去判断字符串去掉括号的情况,如果不满足情况,则继续去除括号

    题解

    DFS

    /**
     *  DFS+剪枝
     *
     *  @param pair         多出来的遇见括号的个数
     *  @param index        记录字符串s的当前位置
     *  @param remove_left  左括号需要删除的个数
     *  @param remove_right 右括号需要删除的个数
     *  @param s            原始字符串
     *  @param solution     生成字符串
     *  @param result       存储所有的字符串结果
     */
    void helper(int pair, int index, int remove_left, int remove_right, const string& s, string solution, unordered_set<string> &result) {
        if (index == s.size()) {
            if (pair == 0 && remove_left == 0 && remove_right == 0)
                result.insert(solution);
            return ;
        }
        
        if (s[index] == '(') {
            // 删除左边括号
            if (remove_left > 0) helper(pair, index + 1, remove_left - 1, remove_right, s, solution, result);
            // 回溯
            helper(pair + 1, index + 1, remove_left, remove_right, s, solution + s[index], result);
        }
        else if (s[index] == ')') {
            // 删除右边括号
            if (remove_right > 0) helper(pair, index + 1, remove_left, remove_right - 1, s, solution, result);
            // 回溯
            if (pair > 0) helper(pair - 1, index + 1, remove_left, remove_right, s, solution + s[index], result);
        }
        else {
            helper(pair, index + 1, remove_left, remove_right, s, solution + s[index], result);
        }
    }
    vector<string> removeInvalidParentheses(string s) {
        int remove_left = 0, remove_right = 0;
        unordered_set<string> result; // 处理重复
        
        // 计算左右两边需要删除括号的个数
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] == '(')
                remove_left++;
            else if (s[i] == ')') {
                if (remove_left > 0) remove_left--;
                else remove_right++;
            }
        }
        
        helper(0, 0, remove_left, remove_right, s, "", result);
        
        return vector<string>(result.begin(), result.end());
    }
    

    BFS

    • 解法1
    bool check(string s) {
        int count = 0;
        for (int i = 0; i < s.size(); i++) {
            char tmp = s[i];
            if (tmp == '(') count++;
            if (tmp == ')') {
                if (count == 0) return false;
                count--;
            }
        }
        return count == 0;
    }
    
    /**
     *  这个解法看似和上面解法类似,以为是DFS,但是其实是个BFS,思路和2是类似的,只不过用递归实现
     *  删除子串的每个字符,然后进行递归
     *
     *
     *  @param begin        记录原字符串的下标,为什么是BFS的原因
     *  @param remove_left  需要删除左边括号的个数
     *  @param remove_right 需要删除右边括号的个数
     *  @param s            子串
     *  @param result       结果
     */
    void helper2(int begin, int remove_left, int remove_right, string s, vector<string> &result) {
        // 如果左右已经没有要删除的括号,并且符合条件,则进行收敛
        if (remove_left == 0 && remove_right == 0) {
            if (check(s)) {
                result.push_back(s);
                return;
            }
        }
        
        // begin是个重点,意味着从begin开始往后删,前面的字符串不再动
        for (int i = begin; i < s.size(); ++i) {
            string temp = s;
            if (remove_left > 0 && remove_right == 0 && s[i] == '(') {
                // 删除子串的每个字符,同时避免重复
                if (begin == i || s[i] != s[i-1]) {
                    temp.erase(i, 1);
                    helper2(i, remove_left-1, remove_right, temp, result);
                }
            }
            if (remove_right > 0 && s[i] == ')') {
                if (begin == i || s[i] != s[i-1]) {
                    temp.erase(i, 1);
                    helper2(i, remove_left, remove_right-1, temp, result);
                }
            }
        }
        
    }
    vector<string> removeInvalidParentheses3(string s) {
        int remove_left = 0, remove_right = 0;
        vector<string> result; // 处理重复
        
        // 计算左右两边需要删除括号的个数
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] == '(')
                remove_left++;
            else if (s[i] == ')') {
                if (remove_left > 0) remove_left--;
                else remove_right++;
            }
        }
        
        helper2(0, remove_left, remove_right, s, result);
        
        return result;
    }
    
    
    • 解法2
    /**
     *  通过从输入字符串中移除每一个括号,生成新的字符串加入到队列中
     *  如果从队列中取出的字符串是有效的,则加入到结果列表中
     *  一旦发现有效的字符串,则不再向队列中补充新的字符串,其去掉的括号数一定是最小的
     *  而此时,队列中存在的元素与队列头元素去掉的括号数的差值 <= 1
     *  并且,只有与队列头元素去掉括号数目相同的元素才有可能是候选答案
     *
     *  @param s <#s description#>
     *
     *  @return <#return value description#>
     */
    vector<string> removeInvalidParentheses2(string s) {
        vector<string> result;
        if (s == "") {
            result.push_back(s);
            return result;
        }
        
        unordered_set<string> visited; // 控制是否访问过字符串,因为要求不可重复
        deque<string> queue;
        queue.push_back(s);
        visited.insert(s);
        
        bool found = false;
        while (!queue.empty()) {
            string temp = queue.front();
            queue.pop_front();
            
            // 每次遍历代表着需要加进来去掉一个括号的子串,层数代表删除括号的次数
            // 只要第一次符合情况了,说明该字符串已经是可去掉括号数目最小的字符串层
            // 意味着该层不再需要加进来任何的子串了,
            if (check(temp)) {
                result.push_back(temp);
                found = true;
            }
            
            if (found) continue;
            for (int i = 0; i < temp.size(); ++i) {
                if (temp[i] != '(' && temp[i] != ')') continue;
                // 删除括号,生成新的字符串
                string str = temp.substr(0, i) + temp.substr(i+1);
                
                if (visited.find(str) == visited.end()) {
                    queue.push_back(str);
                    visited.insert(str);
                }
            }
        }
        
        return result;
    }
    
    
  • 相关阅读:
    支付功能测试用例设计要点
    接口测试用例设计实践总结
    如何高效学习
    性能测试基础总结和自己的理解
    linux安装AWStats业务数据分析工具
    python3登陆接口测试
    Python2和Python3中urllib库中urlencode的使用注意事项
    运用BT在centos下搭建一个博客论坛
    python环境搭建-requests的简单安装(适合新手)
    web 资源好文
  • 原文地址:https://www.cnblogs.com/George1994/p/6399874.html
Copyright © 2011-2022 走看看