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;
}

posted @ 2017-02-15 06:24  banananana  阅读(297)  评论(0编辑  收藏  举报