leetcode 1249. Minimum Remove to Make Valid Parentheses(移除最少的无效括号)

Given a string s of ‘(’ , ‘)’ and lowercase English characters.

Your task is to remove the minimum number of parentheses ( ‘(’ or ‘)’, in any positions ) so that the resulting parentheses string is valid and return any valid string.

Formally, a parentheses string is valid if and only if:

It is the empty string, contains only lowercase characters, or
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.

Example 1:

Input: s = “lee(t©o)de)”
Output: “lee(t©o)de”
Explanation: “lee(t(co)de)” , “lee(t©ode)” would also be accepted.

Example 2:

Input: s = “a)b©d”
Output: “ab©d”

Example 3:

Input: s = “))((”
Output: “”
Explanation: An empty string is also valid.

简单来说就是去除最少的无效括号。即左右括号要成对地匹配。

思路:
方法一:
括号配对一般会想到用stack。
这里stack保存的是左括号的位置,因为左括号多余的话,要把它们删掉,删掉要知道下标吧。
用一个StringBuilder保存 result string, 方便随时修改结果的字符串(input的字符串常量是不能修改的)。

遇到" ( “就在stack中存入下标,我们最后要修改的是result string,怎么判断” ( "在result string中的下标呢?
因为result string是一个一个压入字符保存的,当前长度就是下标。

遇到" ) “,就出栈,同时” ) “保存进result string(匹配的括号)。
如果stack为空,就说明没有与之匹配的” ( “,这时不保存” ) "进result string(等效为已经删掉了)

//33ms
    public String minRemoveToMakeValid(String s) {
        Stack<Integer> stack = new Stack<>();
        StringBuilder result = new StringBuilder();
        
        for(int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if(ch == '(') {
                stack.push(result.length());
                result.append(ch);
            } else if(ch == ')') {
                if(!stack.isEmpty()) {
                    stack.pop();
                    result.append(ch);
                }
            } else {
                result.append(ch);
            }
        }
        
        while(!stack.isEmpty()) {
            result.deleteCharAt(stack.pop());
        }
        return result.toString();
    }

方法二:
不用stack,仅用一个计数变量left, 来记" ( "有多少个。

先把string转为charArray, 因为input的string常量是不能修改的。

然后遍历一遍charArray,遇到" ( "就left ++计数。

遇到" ) “就left --,当left == 0时,说明没有与它匹配的左括号了,当前” ) “需要删除,
删除的操作是最后一起删,这时先把” ) “改为” * "。

上面的遍历可确保没有多余的" ) “了,但是可能还有多余的” ( “,这时left > 0,
从右到左遍历找出这些多余的” ( “, 也改为” * "。

最后直接在原charArray上修改,把" * "的地方跳过即可。

//8ms
    public String minRemoveToMakeValid(String s) {
        char[] chArr = s.toCharArray();
        int left = 0;
        
        //验证左括号的个数,标记多余的右括号为'*'
        for(int i = 0; i < chArr.length; i ++) {
            if(chArr[i] == '(') {
                left ++;
            } else if(chArr[i] == ')') {
                if(left == 0) {
                    chArr[i] = '*';
                } else {
                    left --;
                }
            }
        }
        
        //标记多余(left>0)的左括号为'*'
        for(int i = chArr.length - 1; i >= 0; i--) {
            if(left > 0 && chArr[i] == '(') {        
                left --;
                chArr[i] = '*';              
            }
        }
        
        //把标记的'*'删掉
        int id = 0;
        for(int i = 0; i < chArr.length; i ++) {
            if(chArr[i] != '*') {
                chArr[id] = chArr[i];
                id ++;
            } 
        }
        
        return new String(chArr).substring(0, id);
    }

你可能感兴趣的:(leetcode,leetcode,算法,数据结构)