leetcode 678. Valid Parenthesis String

Given a string containing only three types of characters: '(', ')' and '*', write a function to check whether this string is valid. We define the validity of a string by these rules:

  1. Any left parenthesis '(' must have a corresponding right parenthesis ')'.
  2. Any right parenthesis ')' must have a corresponding left parenthesis '('.
  3. Left parenthesis '(' must go before the corresponding right parenthesis ')'.
  4. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string.
  5. An empty string is also valid.

Example 1:

Input: "()"
Output: True

Example 2:

Input: "(*)"
Output: True

Example 3:

Input: "(*))"
Output: True

Note:

  1. The string size will be in the range [1, 100].

感觉这题比看上去要难,第一感应该是O(n)算法,开始的思路是自左向右遍历消去右括号,保存左括号和符号*的下标。消去利用贪心思想,先消去左括号(从右边的左括号开始消,为了之后更容易匹配*,所以用栈保存遍历到的左括号下标),当左括号消完后,再消符号*(从左边的*开始消,为了之后更容易匹配剩余左括号,所以要用双向队列保存符号*下标)。

消完右括号后,再检查左括号和*是否匹配。时间复杂度O(n),空间复杂度O(n).

public boolean checkValidString(String s) {
        Stack<Integer> stack=new Stack<>();//store the index of '('
        LinkedList<Integer> queue=new LinkedList<>();//store the index of '*'
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)=='*') queue.add(i);
            else if(s.charAt(i)=='('){
                stack.add(i);
            }else{
                if(stack.size()>0) stack.pop();
                else{
                    if(queue.size()==0) return false;
                    queue.remove();
                }
            }
        }
        int count=0;
        while(stack.size()>0){
            while(queue.size()>0&&stack.peek()<queue.peekLast()){
                queue.removeLast();
                count++;
            }
            stack.pop();
            count--;
            if(count<0) return false;
        }
        return true;
    }

感觉到应该还有更简洁的解决方案,看了官方参考答案https://leetcode.com/problems/valid-parenthesis-string/solution/

大致思路是:自左向右遍历时。记录当前最多能匹配多少右括号c1,至少还要匹配多少右括号c2。因为c1的数值对后面的右括号还起作用,要维护这一变量,当某一时刻c1<0时。说明右括号对于左侧过多。c2用于检查左括号,是否对于右侧过多。*号能根据后面右括号的情况而变化,遍历过程中只要c1>=0,就行了。当遍历到一个左括号是,标志着它能用于抵消后面的右括号,也标志着,后面必须要有右括号或*号与其抵消。

时间复杂度O(n),空间复杂度O(1).

感觉这种思路还是较难想到的。。。

public boolean checkValidString(String s) {
        int c1=0,c2=0;
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)==')'){
                c1--;
                c2=Math.max(c2-1,0);
            }else if(s.charAt(i)=='('){
                c1++;
                c2++;
            }else{
                c1++;
                c2=Math.max(c2-1,0);
            }
            if(c1<0) return false;
        }
        return c2==0;
    }

猜你喜欢

转载自blog.csdn.net/yaoct/article/details/85020090
今日推荐