301J. Remove Invalid Parentheses

https://leetcode.com/problems/remove-invalid-parentheses/

这个题非常的磨人,令人感到烦躁。

Method: Best?

class Solution {
    public boolean isValid(String s){
        int count = 0;
        for(int i = 0; i < s.length();i++){
            char c = s.charAt(i);
            if(c == '(') count++;
            if(c == ')') count--;
            if(count < 0) return false; 
            // means the parentheses are already not closed
            // return false immediately
        }
        return count == 0;
    }
    
    public List<String> removeInvalidParentheses(String s) {
        List<String> ans = new ArrayList<>(); // answer list
        
        // represent how many left/right parentheses need to be removed
        int l = 0, r = 0;
        
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            l += c == '(' ? 1: 0;
            if(l == 0){
                //如果左右括号配好对了,第一个出现的是),那么这个是要移除的
                r += c == ')' ? 1:0;
            }else{
                //如果没配好对,如果有有括号,那么就减少一个未配对的。
                l-= c == ')' ? 1:0;
            }
        }
        
        dfs(s,0,l,r,ans);
        return ans;
    }
    
    public void dfs(String s, int start, int l, int r, List<String> ans){
        // 如果合法 就加入答案
        if( l == 0 && r == 0){
            if(isValid(s)){
                ans.add(s);
            }
            return;
        }
        
        //
        for(int i = start; i < s.length(); i++){
            char c = s.charAt(i);
            //这个判断是后面加上的,我们对于重复的部分只删一个且只删第一个。
            if(i != start && c == s.charAt(i-1)) continue;
            //其他字符自动跳过
            //先删右括号,再删左括号,为什么呢?
            // 考虑这么一件事,如果左括号比右括号多,而且只需要删左括号,说明
            // 是这种情况 (((((((()
            // 在需要删左括号的情况下 仍然需要删右括号,说明什么?
            // 说明有多的右括号出现在一串左括号前面了 即 ) (((((((()
            if(r > 0 && c == ')'){
                String temp = i < s.length() ? s.substring(0,i) + s.substring(i+1) : s.substring(0,i);
                dfs(temp, i, l, r-1, ans);
            }else if(l > 0 && c == '('){
                String temp = i < s.length() ? s.substring(0,i) + s.substring(i+1) : s.substring(0,i);
                dfs(temp, i, l-1, r, ans);
            }
            // if(c == '(' || c ==')'){
            //     //这是用来删除第i个字符。
            //     String temp = i < s.length() ? s.substring(0,i) + s.substring(i+1) : s.substring(0,i);
            //     if(r > 0 && c ==')'){
            //         dfs(temp, i, l, r-1, ans);
            //     }else if(l > 0 && c == '('){
            //         dfs(temp, i, l-1, r, ans);
            //     }
            // }
        }
    }
}

2023 的写法 BFS

这个题目确实BFS 比上面的 DFS 更自然,因为它天然的控制了层数 DFS我已经看不懂了 这里技术上要注意的点是,这个图,不保证是一个树: 因此,如果不使用入列之前就加入seen(visited)的话,是会重复入列一个节点的。 如果这样的话,答案中就会有重复的元素,需要用一个 Set 去重。 当然,为了最佳的时间复杂度,应当入列之前就加入 seenSet.

除此之外,对于题目的分析,应该对比和1249的分析。 这两个题乍一看很像,但是之所以这个题这么难,而1249题容易,就是因为本题要求给出所有的 valid 结果。

class Solution {
    /**
    都想不到是个暴力解法 这个题思路就是把这个问题转化成一个图的搜索
    BFS,根节点是s, 子节点是 s 去除任意一个括号 以此类推
    直到暴力搜索了 h 层之后 找到了第一个 valid parenthese 
     */
    public List<String> removeInvalidParentheses(String s) {
        List<String> ans = new ArrayList<>();
        Set<String> seen = new HashSet<>();
        Queue<String> queue = new ArrayDeque<>();
        boolean isValidFound = false;
        queue.offer(s);
        seen.add(s);
        while (!queue.isEmpty() && !isValidFound) {
            int size = queue.size();
            while (size > 0) {
                String cur = queue.poll();
                if (isValidParentheses(cur)) {
                    isValidFound = true;
                    ans.add(cur);
                } else {
                    for (int i = 0; i < cur.length(); i++) {
                        char c = cur.charAt(i);
                        String next = "";
                        if (c == '(' || c == ')') {
                            next = cur.substring(0, i) + cur.substring(i + 1, cur.length());
                            if (!seen.contains(next)) {
                                seen.add(next);
                                queue.offer(next);
                            }
                        }
                    }
                }
                size--;
            }
        }
        return ans;
    }

    private boolean isValidParentheses(String str) {
        int net = 0;
        for (char c : str.toCharArray()) {
            if (c == '(') net += 1;
            if (c == ')') {
                net -= 1;
                if (net < 0) return false;
            }
        } 
        return net == 0;
    }
}

Last updated

Was this helpful?