Leetcode 301. Remove Invalid Parentheses

来源:互联网 发布:护肤品真假查询软件 编辑:程序博客网 时间:2024/05/21 08:51

301. Remove Invalid Parentheses

Total Accepted: 21411 Total Submissions: 63217 Difficulty: Hard

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.

Hide Company Tags
 Facebook
Hide Tags
 Depth-first Search Breadth-first Search
Hide Similar Problems
 (E) Valid Parentheses

思路:

很难的一道题。直接参考别人的解。PS: String类的题目感觉跟算法关系都不大,就是纯考验人的分析能力和耐心的。比如各种string to words转换之类的。


解法一:

参考这里。

BFS。

用了一个set来判断当前string我们有没有遍历过;用一个queue去储存待遍历的candidate。

每次队里取一个string,然后查看是不是valid,如果是加入结果;如果不是,则从字符第一位开始,只要字符是括号,就直接删除当前元素然后入队。

对字符长为N,这一步要产生N-1个 string。

原作者用了个found boolean变量来判断是否已经有满足元素的要求。比如一次之后,产生了N-1个string。然后n-1个string中有2个符合,加入res。found变量保证最小的edit distance,这样就不会加入新的string到队列中(距离为2)。同时原来已经入队的不受found影响,check只要valid就输出。

public class Solution { // 100ms    public List<String> removeInvalidParentheses(String s) {        List<String> res=new ArrayList<>();        if(s==null) return res;        Set<String> visited=new HashSet<>();        Queue<String> queue=new LinkedList<>();        visited.add(s);        queue.add(s);        boolean found=false;        while(!queue.isEmpty()){            int size=queue.size();            for(int i=0;i<size;i++){                s=queue.poll();                if(isValid(s)){                    res.add(s);                    found=true;                }                if(!found){                    for(int j=0;j<s.length();j++){                        if(s.charAt(j)!='('&&s.charAt(j)!=')') continue;                        String t=s.substring(0,j)+s.substring(j+1);                        if(!visited.contains(t)){                            visited.add(t);                            queue.add(t);                        }                    }                }            }            if(found) break; // ensure minimun edit distance        }        return res;    }    private boolean isValid(String s){        int count=0;        for(int i=0;i<s.length();i++){            if(s.charAt(i)=='(') count++;            if(s.charAt(i)==')'&&count--==0) return false;        }        return count==0;    }}

解法二:

参考这里。

并不知道这是DFS还是BFS。

神逻辑:

1. 先check是不是右括号比左括号多。

记录左括号和右括号的数目,如果右括号的数目大于左括号,则说明需要删除一个右括号。

last_j 应该是下一个可以check的位置,叫做firstAvailablePos好些。而last_i则是最新需要check的位置,叫做firstStartPos好些。

这个比上面快很多很多的原因就是它精确的找出来哪几个位置是右括号需要删除,这样是个超级大剪枝。上面的BFS是遍历所有可能性,甚至把左括号删了去做判断。

return的精华在于:

如果s是不满足要求的,那么没有必要再逆向check一次了,也是个超级大剪枝。


2. 1之后,将目前的string逆转(能到这里说明上面的循环全是continue的,也就是右括号多于左括号)。现在逆转string,去判断左括号是不是多于右括号,把上面的步骤再走一遍。

public class Solution { // 3ms    public void remove(String s, List<String> result, int last_i, int last_j, char[] par) {        for (int stack = 0, i = last_i; i < s.length(); i++) {            if (s.charAt(i) == par[0]) stack++;            if (s.charAt(i) == par[1]) stack--;            //如果'('比')'大或等的话,就继续扫下去            if (stack >= 0) continue;            //否则,我们就找到当前有可能删去的')',然后删掉看新的string            for (int j = last_j; j <= i; j++) {                if (s.charAt(j) == par[1] && (j == last_j || s.charAt(j - 1) != par[1])) {                    remove(s.substring(0, j) + s.substring(j + 1, s.length()), result, i, j, par);                }            }            return;        }                String reversed = new StringBuilder(s).reverse().toString();        //如果只从左到右扫了,par[0]还是'('的时候,我们还要再从右往左扫一遍        if (par[0] == '(') {            remove(reversed, result, 0, 0, new char[]{')', '('});        } else {            //否则两遍都扫完了,就加入结果中去            result.add(reversed);        }    }        public List<String> removeInvalidParentheses(String s) {        List<String> result = new ArrayList<String>();        remove(s, result, 0, 0, new char[]{'(', ')'});        return result;    }}

0 0
原创粉丝点击