import java.util.*;

/**
 * NC175 合法的括号字符串
 * @author d3y1
 */
public class Solution {
     /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param s string字符串
     * @return bool布尔型
     */
    public boolean isValidString (String s) {
        // return solution1(s);
        return solution2(s);
        // return solution3(s);
    }

    /**
     * 栈
     * @param s
     * @return
     */
    private boolean solution1(String s){
        Stack<Integer> leftStack = new Stack<>();
        Stack<Integer> starStack = new Stack<>();

        char ch;
        for(int i=0; i<s.length(); i++){
            ch = s.charAt(i);
            if(ch == '('){
                leftStack.push(i);
            }
            else if(ch == '*'){
                starStack.push(i);
            }
            else if(ch == ')'){
                if(!leftStack.isEmpty()){
                    leftStack.pop();
                }else if(!starStack.isEmpty()){
                    starStack.pop();
                }else{
                    return false;
                }
            }
        }

        while(!leftStack.isEmpty()){
            if(!starStack.isEmpty() && leftStack.peek()<starStack.peek()){
                leftStack.pop();
                starStack.pop();
            }else{
                return false;
            }
        }

        return true;
    }

    /**
     * 贪心
     * @param s
     * @return
     */
    private boolean solution2(String s){
        // 待消除左括号的最小个数
        int minLeft = 0;
        // 待消除左括号的最大个数
        int maxLeft = 0;

        for(char ch: s.toCharArray()){
            if(ch == '('){
                minLeft++;
                maxLeft++;
            }
            else if(ch == '*'){
                // * -> )
                if(minLeft > 0){
                    minLeft--;
                }
                // * -> (
                maxLeft++;
            }
            else if(ch == ')'){
                if(minLeft > 0){
                    minLeft--;
                }
                // 已经没有'('或'*'与当前')'匹配
                if(maxLeft == 0){
                    return false;
                }
                maxLeft--;
            }
        }

        return minLeft==0;
    }

    /**
     * 动态规划
     *
     * dp[i][j]表示子串s[i,j]是否为合法的括号字符串
     * 
     * len=1:
     * dp[i][i] = true , s.charAt(i) == '*'
     * 
     * len=2:
     * dp[i][i+1] = true , (currCh=='('||currCh=='*') && (nextCh==')'||nextCh=='*')
     * 
     * len>=3:
     * dp[i][j] = dp[i+1][j-1] , (leftCh=='('||leftCh=='*') && (rightCh==')'||rightCh=='*')
     * dp[i][j] = dp[i][k]&&dp[k+1][j] , i<=k<j&&!dp[i][j]
     * 
     * @param s
     * @return
     */
    private boolean solution3(String s){
        int n = s.length();

        boolean[][] dp = new boolean[n][n];

        // len=1 -> *
        for(int i=0; i<n; i++){
            if(s.charAt(i) == '*'){
                dp[i][i] = true;
            }
        }

        // len=2 -> () (* *) **
        char currCh,nextCh;
        for(int i=0; i+1<n; i++){
            currCh = s.charAt(i);
            nextCh = s.charAt(i+1);
            if((currCh=='('||currCh=='*') && (nextCh==')'||nextCh=='*')){
                dp[i][i+1] = true;
            }
        }

        // len>=3
        char leftCh,rightCh;
        for(int i=n-3; i>=0; i--){
            for(int j=i+2; j<n; j++){
                leftCh = s.charAt(i);
                rightCh = s.charAt(j);
                // (())
                if((leftCh=='('||leftCh=='*') && (rightCh==')'||rightCh=='*')){
                    dp[i][j] = dp[i+1][j-1];
                }
                // ()()
                for(int k=i; k<j&&!dp[i][j]; k++){
                    dp[i][j] = dp[i][k]&&dp[k+1][j];
                }
            }
        }

        return dp[0][n-1];
    }
}