LeetCode 301 Remove Invalid Parentheses (BFS + 剪枝)

66 篇文章 0 订阅
60 篇文章 0 订阅

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.


题目链接:https://leetcode.com/problems/remove-invalid-parentheses/


题目分析:先写一个可以通过的再一步步优化,题目要求删除最少个数使得合法,那么显然BFS搞一搞,就出来了一个142ms的代码
public class Solution {
    
    class Data {
        String s;
        int cnt;
        
        Data(String s, int cnt) {
            this.s = s;
            this.cnt = cnt;
        }
    }
    
    public List<String> removeInvalidParentheses(String s) {
        Queue<Data> q = new LinkedList<>();
        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();
        q.add(new Data(s, 0));
        int cnt = Integer.MAX_VALUE;
        boolean flag = false;
        while (q.size() > 0) {
            Data cur = q.poll();
            if (isValid(cur.s)) {
                if (!flag) {
                    flag = true;
                    cnt = cur.cnt;
                }
                if (cur.cnt == cnt) {
                    list.add(cur.s);
                }
                else {
                    return list;
                }
            }
            int len = cur.s.length();
            for (int i = 0; i < len; i ++) {
                if(cur.s.charAt(i) == '(' || cur.s.charAt(i) == ')') {
                    String tmp = cur.s.substring(0, i) + cur.s.substring(i + 1, len);
                    if (!set.contains(tmp)) {
                        set.add(tmp);
                        q.add(new Data(tmp, cur.cnt + 1));
                    }
                }
            }
        }
        return list;
    }
    
    boolean isValid(String s) {
        int len = s.length();
        int l = 0;
        for (int i = 0; i < len; i ++) {
            if (s.charAt(i) == '(') {
                l ++;
            }
            else if (s.charAt(i) == ')'){
                l --;
            }
            if (l < 0) {
                return false;
            }
        }
        return l == 0;
    }
}


其实发现这个Data类是多余的,或者说不需要记录cnt,由于BFS是广度优先,或者说一层一层的搜,所以某层求得解后标记一下即可,这样又得到了95ms的代码
public class Solution {
    
    public List<String> removeInvalidParentheses(String s) {
        Queue<String> q = new LinkedList<>();
        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();
        boolean flag = false;
        q.add(s);
        while (!q.isEmpty()) {
            String cur = q.poll();
            if (isValid(cur)) {
                list.add(cur);
                flag = true;
                if (q.isEmpty()) {
                    return list;
                }
            }
            if (!flag) {
                int len = cur.length();
                for (int i = 0; i < len; i ++) {
                    if(cur.charAt(i) == '(' || cur.charAt(i) == ')') {
                        String nxt = cur.substring(0, i) + cur.substring(i + 1, len);
                        if (set.add(nxt)) {
                            q.add(nxt);
                        }
                    }
                }
            }
        }
        return list;
    }
    
    boolean isValid(String s) {
        int len = s.length();
        int l = 0;
        for (int i = 0; i < len; i ++) {
            if (s.charAt(i) == '(') {
                l ++;
            }
            else if (s.charAt(i) == ')'){
                l --;
            }
            if (l < 0) {
                return false;
            }
        }
        return l == 0;
    }
}


接着可以发现若合法,那么第一个括号必然是左括号,最后一个必然是右括号,这里预处理一下变成42ms,在枚举删除点的时候,连续重复的括号只需要删除一个,这里判断一下变成33ms,其实还有能优化的地方。。。discuss里有3ms DFS的大神。。。
public class Solution {
    
    //42ms
    public String removeHelper(String s) {
        int len = s.length();
        if (len == 0) {
            return s;
        }
        int i = 0, j = len - 1;
        while (i < j && s.charAt(i) == ')') {
            i ++;
        }
        while (i < j && s.charAt(j) == '(') {
            j --;
        }
        return s.substring(i, j + 1);
    }
    
    public List<String> removeInvalidParentheses(String s) {
        Queue<String> q = new LinkedList<>();
        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();
        boolean flag = false;
        q.add(removeHelper(s));
        while (!q.isEmpty()) {
            String cur = q.poll();
            if (isValid(cur)) {
                list.add(cur);
                flag = true;
                if (q.isEmpty()) {
                    return list;
                }
            }
            if (!flag) {
                int len = cur.length();
                for (int i = 0; i < len; i ++) {
                    if(cur.charAt(i) == '(' || cur.charAt(i) == ')') {
                        //33ms
                        if (i + 1 < len && cur.charAt(i) == cur.charAt(i + 1)) {
                            continue;
                        }
                        String nxt = cur.substring(0, i) + cur.substring(i + 1, len);
                        if (set.add(nxt)) {
                            q.add(nxt);
                        }
                    }
                }
            }
        }
        return list;
    }
    
    boolean isValid(String s) {
        int len = s.length();
        int l = 0;
        for (int i = 0; i < len; i ++) {
            if (s.charAt(i) == '(') {
                l ++;
            }
            else if (s.charAt(i) == ')'){
                l --;
            }
            if (l < 0) {
                return false;
            }
        }
        return l == 0;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值