32. Longest Valid Parentheses

最长有效括号子串的求解方法
博客围绕求解包含 '(' 和 ')' 字符的字符串中最长有效括号子串的问题展开。作者起初想法有误,后意识到可用栈判断,还提到栈为空时计算有效对。解答部分介绍了三种方法,包括用栈、动态规划以及不使用额外空间的解法。

题目

Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: “(()”
Output: 2
Explanation: The longest valid parentheses substring is “()”

Example 2:

Input: “)()())”
Output: 4
Explanation: The longest valid parentheses substring is “()()”

我的想法

一开始只看了example,以为是判断连续的"()",submit的时候才发现是判断有效括号

//理解错误
class Solution {
    public int longestValidParentheses(String s) {
        int res = 0; 
        if(s == null || s.indexOf("()") == -1) return res;
                    
        while(s.indexOf("()") != -1 && s.length() > 1){
            int count = 0;
            s = s.substring(s.indexOf("()"));
            while(s.indexOf("()") == 0){
                count += 2;
                s = s.substring(2);
            }
            if(count > res) res = count;                           
        }
        return res;
    }
}

可以用栈来进行判断,"("入栈,")"出栈。如果正向循环结束栈不为空,则说明结尾处有不匹配的现象,进行反向循环。但对于")()())()()("这种正向正确,反向不匹配的无法进行判断

    public int longestValidParentheses(String s) {
        if(s == null || s.length() < 2) return 0;
        Deque<Character> stack = new ArrayDeque<Character>();
        int count = 0, res = 0;
        
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) == '(') stack.push('(');
            else{
                if(stack.isEmpty()){
                    count = 0;
                    continue;
                }
                stack.pop();
                count++;
                res = count>res ? count : res;
            }
        }        
        if(!stack.isEmpty()){
            int recount = 0;
            Deque<Character> stack2 = new ArrayDeque<Character>();
            for(int i = s.length()-1; i >= 0; i--){
                if(s.charAt(i) == ')') stack2.push(')');
                else{
                    if(stack2.isEmpty()){
                        recount = 0;
                        continue;
                    }
                    stack2.pop();
                    recount++;    
                    res = recount>res ? recount : res;
                }
            }
        }
        
        return res*2;
    }

根据solution3的提示找到问题所在:应该在栈为空的时候计算有效对

class Solution {
    public int longestValidParentheses(String s) {
        if(s == null || s.length() < 2) return 0;
        Deque<Character> stack = new ArrayDeque<Character>();
        int count = 0, res = 0;
        
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) == '(') stack.push('(');
            else{
                if(stack.isEmpty()){//不能在这计算有效对,如果完全匹配则无法判断
                    count = 0;
                    continue;
                }
                stack.pop();
                count++;
                //不能在这计算有效对,如果出栈不完全,会导致误认
            }
            if(stack.isEmpty()) res = count>res ? count : res;
        }
        
        
        if(!stack.isEmpty()){
            int recount = 0;
            Deque<Character> stack2 = new ArrayDeque<Character>();
            for(int i = s.length()-1; i >= 0; i--){
                if(s.charAt(i) == ')') stack2.push(')');
                else{
                    if(stack2.isEmpty()){
                        recount = 0;
                        continue;
                    }
                    stack2.pop();
                    recount++;                    
                }
                if(stack2.isEmpty()) res = recount>res ? recount : res;
            }
        }
        
        return res*2;
    }
}

解答

leetcode solution 1: Using Stack
把序号压入栈中,可以通过序号查直接计算长度

public class Solution {
    public int longestValidParentheses(String s) {
        int maxans = 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } 
            else {
                stack.pop();
                if (stack.empty()) stack.push(i);
                else maxans = Math.max(maxans, i - stack.peek());
            }
        }
        return maxans;
    }
}

leetcode solution 2: Using Dynamic Programming
分为两种情况:(()(())

  1. s[i] == ')' && s[i-1] == '(''......()'dp[i]=dp[i−2]+2
  2. s[i] == ')' && s[i-1] == ')''......))',需要判读是否s[i - dp[i-1] - 1] == '(',即前面是否能与之配对。如果等于。则dp[i] = dp[i−1] + dp[i−dp[i−1]−2] + 2,其中dp[i−dp[i−1]−2]类似于dp[i−2],即前项的有效括号数
public class Solution {
    public int longestValidParentheses(String s) {
        int maxans = 0;
        int dp[] = new int[s.length()];
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                    dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
                } 
                else if (i - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                    dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
                }
                maxans = Math.max(maxans, dp[i]);
            }
        }
        return maxans;
    }
}

leetcode solution 3: Without extra space
感觉跟这道题的解法很像42. Trapping Rain Water
用left和right的++来表示出入栈,省空间。对于结尾处不完整的

public class Solution {
    public int longestValidParentheses(String s) {
        int left = 0, right = 0, maxlength = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                left++;
            } 
            else {
                right++;
            }
            if (left == right) {//空栈
                maxlength = Math.max(maxlength, 2 * right);
            } 
            else if (right >= left) {//不匹配
                left = right = 0;
            }
        }
        left = right = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                left++;
            } 
            else {
                right++;
            }
            if (left == right) {
                maxlength = Math.max(maxlength, 2 * left);
            } 
            else if (left >= right) {
                left = right = 0;
            }
        }
        return maxlength;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值