LeetCode Top 100 Liked Questions 32.Longest Valid Parentheses(Java版; Hard)

welcome to my blog

LeetCode Top 100 Liked Questions 32.Longest Valid Parentheses(Java版; Hard)

题目描述

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 "()()"
class Solution {
    public int longestValidParentheses(String s) {
        int n = s.length();
        if(n<2){
            return 0;
        }
        //dp[i]表示以s[i]结尾时的有效括号长度
        //dp[i] = dp[i-2] + 2  if s[i-1]=='('
        //dp[i] = dp[i-dp[i-1]-2] + dp[i-1] + 2   if s[i-1]==')' && s[i-dp[i-1]-1] == '('
        int[] dp = new int[n];
        int max = 0;
        char[] chs = s.toCharArray();
        for(int i=0; i<n; i++){
            if(chs[i]==')'){
                if(i-1>=0 && chs[i-1]=='('){
                    dp[i] = 2 + (i-2>=0?dp[i-2]:0);
                }else if(i-1>=0 && i-dp[i-1]-1>=0 && chs[i-1]==')'&&chs[i-dp[i-1]-1]=='('){
                    dp[i] = dp[i-1] + 2 + (i-dp[i-1]-2>=0?dp[i-dp[i-1]-2] : 0 );
                }
            }

            max = Math.max(max, dp[i]);
        }
        return max;
    }
}
第一次做, 从左右和从右两次遍历字符串; 记录’(‘和’)'出现的次数, 分别用left和right表示; 从左往右遍历时, 如果left<right, 说明以当前位置作为结尾不是有效的括号, 如果left==right, 说明是有效的括号, left+right就是括号的长度; 再从右往左遍历, 如果left>right, 说明以当前位置作为结尾不是有效的括号, 如果left==right,说明是有效的括号, left+right就是括号的长度; 只从左往右遍历一遍会漏解: “(()”, 返回0
  • 核心: 从左往右遍历时, 如果left<right, 说明以当前位置作为结尾不是有效的括号; 从右往左遍历时, 如果left>right, 说明以当前位置作为结尾不是有效的括号; 如果left==right, 说明是有效的括号, left+right就是括号的长度
class Solution {
    public int longestValidParentheses(String s) {
        if(s==null || s.length()<2)
            return 0;
        int left=0, right=0;
        int max=0;
        //从左往右遍历
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i)=='(')
                left++;
            else
                right++;
            if(right>left){//此时以s.charAt(i)结尾不是有效的括号
                left=0;
                right=0;
            }
            else if(left == right)
                max = Math.max(max, left + right);
        }
        //从右往左遍历
        left=0;
        right=0;
        for(int i=s.length()-1; i>=0; i--){
            if(s.charAt(i)=='(')
                left++;
            else
                right++;
            if(left>right){
                left=0;
                right=0;
            }
            else if(left==right)
                max = Math.max(max, left+right);
        }
        return max;
    }
}
第一次做, 使用栈, 速度比动态规划慢(18ms VS 4ms); 压入栈的是字符的索引; 需要引入参考计算有效括号的长度,这是最妙的! 最开始向往栈中压入-1作为参考; 只有一种情况下会更新参考, 注意如何更新参考
/*
使用栈
压入'('的索引, 而不是'(', 这样方便判断长度
栈如何处理这种情况: ")()())", 要想顺利处理这种情况, 就不能通过i - x + 1的计算长度了, 这种方式只能正确计算(())这种情况, 不能正确计算()()这种情况的长度
正确做法是在()()前面放个参考,让最后一个)的索引减参考的索引就是()()的长度
所以最开始的时候需要将-1压栈,作为参考
要注意如何更新参考: 当栈为空的时候, 说明刚刚出栈的就是参考, 说明此时s.charAt(i)不能配对, 把当前i的入栈, 作为新的参考
*/
import java.util.Stack;

class Solution {
    public int longestValidParentheses(String s) {
        if(s==null || s.length()<2)
            return 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        int max = 0;
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i)=='('){
                stack.push(i);
            }
            else{//here, s.charAt(i)==')'
                int temp = stack.pop();
                if(stack.isEmpty()){//栈为空, 说明刚刚弹出的是参考, 不能和s.charAt(i)配对
                    stack.push(i);//将当前索引i压栈, 作为新的参考
                }
                else{
                    max = Math.max(max, i - stack.peek());
                }
            }
        }
        return max;
    }
}
第一次做, 动态规划版, 看了题解的思想后, 写出来了, 但是写得比题解长很多, 条件判断比较多, 时刻注意越界检查; 核心:dp[i]表示以s.charAt(i)结尾的有效括号的最大长度, s.charAt(i)必须是’)’, 继续根据dp[i-1]是’(‘还是’)'分成两种情况讨论
/*
动态规划dp[i]表示, 以s.charAt(i)结尾的有效括号长度
如果dp[i]=='(' , 则dp[i]=0
如果dp[i]==')',则根据dp[i-1]是'('还是')'分成两种情况讨论
*/
class Solution {
    public int longestValidParentheses(String s) {
        if(s==null || s.length()<2)
            return 0;
        int[] dp = new int[s.length()];
        int max = 0;
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i) == '(')
                dp[i]=0;
            else{
                if(i-1>=0 && s.charAt(i-1)=='('){
                    if(i-2>=0)
                        dp[i] = dp[i-2] + 2;
                    else
                        dp[i] = 2;
                }
                else if(i-1>=0 && s.charAt(i-1)==')'){
                    if(i-dp[i-1]-2>=0 && s.charAt(i-dp[i-1]-1)=='(')
                        dp[i] = dp[i-dp[i-1]-2] + dp[i-1] + 2;
                    else if(i-dp[i-1]-1>=0 && s.charAt(i-dp[i-1]-1)=='(')
                        dp[i] = dp[i-1] + 2;
                }
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}
题解, 动态规划版
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] > 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;
    }
}
题解, 左右两次遍历
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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值