20. https://leetcode.com/problems/valid-parentheses/description/

678. https://leetcode.com/problems/valid-parenthesis-string/description/

32. https://leetcode.com/problems/longest-valid-parentheses/description/

22. https://leetcode.com/problems/generate-parentheses/description/

856. https://leetcode.com/problems/score-of-parentheses/description/

301. https://leetcode.com/problems/remove-invalid-parentheses/description/

921.  https://leetcode.com/problems/minimum-add-to-make-parentheses-valid/description/

 

20 Valid Parentheses

Easy 题,判断括号是否匹配,显然用stack 解决,唯一需要注意的是如果stack 为空时 pop 会抛出异常,在抛出异常时说明不满足条件。

 例: "()[]{}"  符合匹配。 
try{
   char c = st.pop();
}
catch (Exception e){
    return false;
}

 

 678. Valid Parenthesis String

   这题为升级版的 20  Valida parenthesis,里面加了 *, * 可以匹配 一个 ( 或者 一个 ) 或者不匹配任何。

 

 

32. Longest Valid Parentheses

给定一组小括号求最长的匹配。 

例: "( ) ( ( ) ( )" , 如果一开始遇到符合的匹配,但后面的匹配不满足条件 则 重新开始计算,本例中 最长的是 后面 4个括号,返回4.

算法:  本题属于hard 题, 用stack, 但stack 里存放的不是 括号,而是 括号的Index。 

1. 现在 stack 里放入 -1

2.  如果遇到 "("  就把 index push stack, 遇到 ")" 先 pop 然后  拿 " )" 的 index - stack.peek()。 假设 (), stack :- 1 ,0 , 在遇到第一个 ) 时 先 pop 0, 再 拿 ) 的index 1 - (-1) = 2. 但这个算法有个问题就是 假如 stack pop 后 为empty, 例如  “)” , stack -1, 遇到 ) 时, 先 pop -1, 此时 stack 为空, 因此在每次 index - stack.peek() 时 得先判断 stack 是否empty, 如果 empty 那么就把当前 ) 的 index  push stack ,相当于 起始时插入的-1. 

   例如: ")()" 

stack: -1
) : pop -1, 此时stack is empty, 因此 push 0,
( push 1
): pop 1, index 2 , 2 - stack.peek() = 2 -0 = 2. 因此遇到 ) 并且 stack 为 empty 时 把 ) 的index push , 相当于重新建立start index.

代码非常简单,只是 插入 index 到stack 里的算法很难想。
class Solution {
    public int longestValidParentheses(String s) {
        if(s == null || s.length() ==0) return 0;
        
        Stack<Integer> st = new Stack<>();
        st.push(-1);
        
        int max = 0;
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i) == '(')  st.push(i);
            
            else {
                st.pop();
                if(st.isEmpty()){
                    st.push(i);  
                }
                max = Math.max(max,i-st.peek());
            }                                   
        }     
        return max;      
    }
}

 

22. Generate Parentheses

    给定n , 生成所有 可能的 括号匹配的组合, 不要求输出括号的顺序。

    例如 n = 3, 共有 如下的组合: 

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

分析: 1. 任何时候都得先 放左括号 2. 任何时候 右括号 ) 个数都不能比( 个数多。
显然用DFS, 设计如下 DFS的函数接口:

dfs(int numLeft, int numRight, String str, List<String> result, int n)

dfs 终止条件 为 numRigth == n,
1. 当 numLeft == numRight 时, 只能放 左括号 (
2. 当 numLeft > numRight时 有两种情况
2.1 放右括号 )
2.2 当 numLeft<n 时, 可以放左括号 (. 第一次的code 忘记了加判断条件 numLeft<n 结果 内存溢出了。

        dfs 调用   dfs(1,0, "(", result, n), code 如下:

class Solution {
    public List<String> generateParenthesis(int n) {
        
        List<String> result = new ArrayList<>();

        helper(1,0,"(", n, result);
        
        return result;
    }
    
    private void helper(int numLeft, int numRight, String str, int n, List<String> result){
        
        if(numRight == n){
            result.add(str);
        }
        
        else if(numLeft == numRight){ // add ( 
            helper(numLeft+1, numRight, str+"(", n,result);
        }
        
        else if(numLeft > numRight){
            helper(numLeft, numRight+1, str+")",n,result);
            if(numLeft<n)
               helper(numLeft+1, numRight, str+"(", n,result);
                
            }
        }
}

 此题虽然为简单 DFS, 但有多种DFS 的写法,待分析。

 

 

921. Minimum Add to Make Parentheses Valid

问你最少添加多少个括号让括号字符串变成 balanced.
例如 "())", ans = 1
")))" ans = 3
"(()(" ans = 2

算法: 构造一个stack, 遇到left ( 放入, 遇到 right ) 就pop, 在pop 前判断 stack 是否为empty ,如果是说明 left 少了一个括号, ans ++
扫描完字符串后 再统计 stack 里还剩多少个 (, 说明还缺这么多个 right ) , return ans + stack.size()
code 也非常简单:
class Solution {
    public int minAddToMakeValid(String S) {
        Stack<Character> st = new Stack<>();
        
        int sum = 0;
        for(char c: S.toCharArray()){
            if(c == '(') st.push('(');
            
            else {
                if(st.isEmpty()) sum++;
                else st.pop();
            }
        }      
        return sum+=st.size(); 
    }
}

 改进: solution 里给的算法, 不需要额外的stack, space 为O(1) ,但思想和上面用stack 的是一致的。

  遇到 (  ans +1, 遇到 ) 再 ans -1,  这样如果本身是balanced 最后 ans ==0.

  1. 在每次 发现ans == -1 时,说明  多了个 right ) , 这样 bla ++, 并且把 ans 重新置0

   2. 最后的结果中 ans 为额外的 left (,   bla 为额外的 ), 加一起就是需要的result

class Solution {
    public int minAddToMakeValid(String S) {    
        int ans = 0;
        int bla = 0;
        for(char c: S.toCharArray()){
            ans += c =='(' ? 1:-1;
            if(ans == -1){  // 说明多了 ) 括号, 因此 bla ++, 然后 ans 重新回0
                ans = 0;
                bla++;
            }
        }   
        return ans+bla; // 最后ans 的个数为额外的 (, bla 为多出的 ). 例如 ))) (( , 那么 bla = 3, ans = 2     
    }
}

 

856. Score of Parentheses
  • () has score 1
  • AB has score A + B, where A and B are balanced parentheses strings.
  • (A) has score 2 * A, where A is a balanced parentheses string.
Input: "(()(()))"
Output: 6

算法一: 参考solution 中 stack 的解法,不管什么组合 本质都是由 add + sum*2 组合而成的。
特例: 如果是 () 可以认为是 0+ 2*0 =0, 直接赋值为1.
算法就2步:
1. 初始化: push 0 to stack, 可以认为一开始的加数为0
2. 在遇到 left ( 时往 stack 里放0, 在遇到 right ) 从stack 里 pop 两次, 第一个pop 为sum, 计算 2*sum, 第二个 pop 为add
例如 (()) , 1. 0, 2. ( 0 0 3. (( 0 0 0, 4. ) , pop 出两个0, 第一次 2*0+0 ==0, 为特例 记作1. 将sum push 回 stack, 此时 stack 为 0,1 5, ) 从stack 里 pop 两次 , 变成 2*1 +0 = 2.
例如 () (()), 1. 遇到第一个 () 后, stack 为 1, 2. ( ( stack 为 1, 0,0 3. ) pop 两次 计算结果后 stack 为 1,1 4.) pop 出两个1, 计算结果为 1+2*1 = 3.
class Solution 
{
public int scoreOfParentheses(String S) {
    Stack<Integer> stack = new Stack<>();
    stack.push(0);
    //int score = 0;
    
    for(char c: S.toCharArray()){
        if(c == '(') stack.push(0);
        else {
            int sum = stack.pop();
            int add = stack.pop();
            int cur_score = Math.max(sum*2,1)+add;
            stack.push(cur_score);
        }
    }
    return stack.pop();
 }
    
}

 算法二: 同样用stack 只是 stack里存放 是左右括号。 

                 算法:  只有乘法和加法运算,可以表示成例如:  A(B+C(D+E)) 对于这样只有乘法和加法的运算,不一定要从括号里面先算,而是可以 等价成 AB+ AC*D+AC*E 

                 任何时候遇到一个封闭的一对括号 () 可以先看外面嵌套了基层括号, 直接 拿2^层数, 下一个 封闭的() 也是如此 再加上一步的和。

                 具体算法: 用一个stack, 遇到 “(” 就入栈,  遇到 ) 时,先直接 pop,再  看 index -1 时 是否是(,  如果是 则可以组成完整的 (), 然后stack 的size 就是层数, 如果 index- 1 也是) 则直接忽略就可以。

                例如  (( () () ) )  , 1. 遇到 第一个) 时, stack 里有3个 (, 先pop 一次 剩下2个( , 因为 上一个字符是 (, 此时 ans += 2^stack_size = 4,   2.  遇到 第二个 ) 时, 先pop 后 ,此时 stack 里还有两个(, 然后  ans += 2^stack_size = 8,  3. 最后一个) 时,因为上一个是) 先pop  ,然后直接跳过。

class Solution 
{
public int scoreOfParentheses(String S) {
    Stack<Character> stack = new Stack<>();
    int ans = 0;
    
    for(int i=0; i<S.length(); i++){
        if(S.charAt(i) == '(') stack.push('(');
        
        else{
            stack.pop();
            if(S.charAt(i-1) == '(') ans += Math.pow(2,stack.size());
            //else 如果是 )) 则忽略
        }
    }
    
    return ans;    
}
    
}

 



posted on 2018-11-04 01:20  KeepAC  阅读(160)  评论(0编辑  收藏  举报