LeetCode 刷题记录 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 “()()”

解法1:
用栈解决
假设有字符串 “) ( ) ( ) ) ( ( ( ( ) ) ) (”
start代表有效括号开始的位置,初始化为-1
遍历字符串
第一个是 ) 栈为空,此时无有效的(与它匹配,故将start的值变为i = 0
第二个是 ( 将i值入栈,此时栈: 1
第三个是 ) 栈不为空,说明有有效的(与它匹配,将左括号退栈,此时栈为空,将匹配的左括号退栈后再次检查栈是否为空
为空 :说明此时没有多余的(阻断有效的括号,我们可以通过 i - start来计算长度,此时为2 - 0 = 2,更新最大长度2
第四个是 ( 将i值入栈,此时栈: 3
第五个是 ) 栈不为空,说明有有效的(与它匹配,将左括号退栈,此时栈为空,将匹配的左括号退栈后再次检查栈是否为空
为空 :说明此时没有多余的(阻断有效的括号,我们可以通过 i - start来计算长度,此时为4 - 0 = 2,更新最大长度4
第六个是 ) 栈为空,此时无有效的(与它匹配,说明有非法的)阻断有效的字符串,故将start的值变为i = 5
7、8、9都是(,入栈,此时栈:6,7, 8
第十个是 ) 栈不为空,说明有有效的(与它匹配,将左括号退栈,此时栈为空,将匹配的左括号退栈后再次检查栈是否为空
此时栈:6,7,栈不为空,此时有多余的(阻断有效括号,我们不能用i - start来计算长度,应该用 i - st.top(),即9 -7 = 2,更新最大长度4
第十一个是 ) 栈不为空,说明有有效的(与它匹配,将左括号退栈,此时栈为空,将匹配的左括号退栈后再次检查栈是否为空
此时栈:6,栈不为空,此时有多余的(阻断有效括号,我们不能用i - start来计算长度,应该用 i - st.top(),即10 -6 = 4,更新最大长度4
第十二个是 ( 将i值入栈,此时栈: 6,11
结束算法

c++:

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> st;
        int maxLen = 0;
        int start = -1;
        int n = s.size();
        for(int i = 0; i < n; i++){
            if(s[i] == '('){
                st.push(i);
            } else {
                if(st.empty()){
                    start = i;
                } else{
                    st.pop();
                    if(st.empty()){
                        maxLen = max(maxLen, i - start);
                    } else {
                        maxLen = max(maxLen, i - st.top());
                    }
                }
                
            }
        }
        return maxLen;
    }
};

java:

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

python:

class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        st = []
        maxLen = 0;
        start = -1;
        n = len(s)
        for i in xrange(n):
            if s[i] == '(':
                st.append(i)
            else:
                if not st:
                    start = i
                else:
                    st.pop()
                    if not st:
                        maxLen = max(maxLen, i - start)
                    else:
                        maxLen = max(maxLen, i - st[-1])
                    
                
        return maxLen

解法1的变体:
为了实现两种计算长度的统一, i - st.top()和i - start,我们将要更新start值时将start值压入栈中,这样统一用 i - st.top()就可以了
java:

public class Solution {

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

解法1的变体2:
假设有字符串“())()((())”
首先初始化栈[0]
第一个是(: 是左括号,追加0,此时栈[0,0]
第二个是 ): 是右括号,查看栈中数字的数量,大于1说明有可以匹配的(,取出栈中此时的括号数量,为0,更新括号数量此时栈[2],更新最大的括号的数量,2
第三个是 ):是右括号,查看栈中数字的数量,为1,说明没有可以匹配的(,说明有不合法的),将栈初始化[0]
第四个是 (:是左括号,追加0,此时栈[0,0]
第五个是 ): 是右括号,查看栈中数字的数量,大于1说明有可以匹配的(,取出栈中此时的括号数量,为0,更新括号数量此时栈[2],更新最大的括号的数量,2
6,7,8都是(,此时栈[2,0,0,0]
第九个是 ): 是右括号,查看栈中数字的数量,大于1说明有可以匹配的(,取出栈中此时的括号数量,为0,更新括号数量此时栈[2,0,2],更新最大的括号的数量,2
第十个是 ): 是右括号,查看栈中数字的数量,大于1说明有可以匹配的(,取出栈中此时的括号数量,为2,更新括号数量此时栈[2,4],更新最大的括号的数量,4

python:

class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        st = [0]
        maxLen = 0
        for c in s:
            if c == '(':
                st.append(0)
            else:
                if len(st) > 1:
                    val = st[-1]
                    st.pop()
                    st[-1] += val + 2
                    maxLen = max(st[-1], maxLen)
                    
                   
                else:
                    st = [0]
                    
                
        return maxLen

解法2:
DP:
dp[i]表示为在位置i结尾的的有效括号长度
由定义知所有(的位置dp值都为0,因为以(结尾的都不是有效括号
在程序中我们只需处理)的dp值
假设有字符串“())()(())”
从第二个开始
第二个是),i-1 的字符是(,说明匹配成功个数在dp[i-2]的基础上增加了2,dp数组[0,2,0,0,0,0,0,0,0],更新最大长度2
第三个是),i-1的字符不是(,这时候可能匹配的(可能在前边,已知dp[i-1]的值为x,说明位置i-1结尾的的有效括号长度为x,所以我们要越过x个位置去找匹配的(,具体来说就是位置i - dp[i-1] - 1,此时匹配的(不存在, dp数组[0,2,0,0,0,0,0,0,0],更新最大长度2
第四个是(,不做处理,dp数组[0,2,0,0,0,0,0,0,0]
第五个是),i-1 的字符是(,说明匹配成功个数在dp[i-2]的基础上增加了2,dp数组[0,2,0,2,0,0,0,0,0],更新最大长度2
第六个是(,不做处理,dp数组[0,2,0,2,0,0,0,0,0]
第七个是(,不做处理,dp数组[0,2,0,2,0,0,0,0,0]
第八个是),i-1 的字符是(,说明匹配成功个数在dp[i-2]的基础上增加了2,dp数组[0,2,0,2,0,0,0,2,0],更新最大长度2
第三个是),i-1的字符不是(,这时候可能匹配的(可能在前边,已知dp[i-1]的值为2,说明位置i-1结尾的的有效括号长度为2,所以我们要越过2个位置去找匹配的(,具体来说就是位置j = i - dp[i-1] - 1 = 8 - 2 - 1 = 5,此时对应的是可以匹配的(,dp[i] = dp[i-1] + 2,此时还要关注前面是否有可以接上的有效括号,即再加上dp[j - 1] ,如此时dp[4] = 2,说明前面有可以接上的2个有效括号, dp数组[0,2,0,0,0,0,0,2,6],更新最大长度6

注意点:

  1. dp[i] = (i - 2) >= 0 ? dp[i-2] + 2 : 2 最后要加的是2而不是0
  2. dp[i] = dp[i-1] + 2 + ((j - 1) >= 0 ? dp[j - 1] : 0) 注意我们要加的是最后三元表达式的值,所以三元表达式要加括号
    不能写成 dp[i] = dp[i-1] + 2 + (j - 1) >= 0 ? dp[j - 1] : 0 这样会先加dp[i-1] + 2 + (j - 1)的值,然后看是否>=0,然后返回dp[j - 1]或者0
    原因是加减乘除优先级要大于比较

c++:

class Solution {
public:
    int longestValidParentheses(string s) {
        int maxLen = 0;
        int n = s.size();
        vector<int> dp(n, 0);
        for(int i = 1; i < n; i++){
            if(s[i] == ')'){
                if(s[i-1] == '('){
                    dp[i] = (i - 2) >= 0 ? dp[i-2] + 2 : 2;
                } else {
                    int j = i - dp[i-1] - 1;
                    
                    if(j >= 0 && s[j] == '('){
                       
                        
                        dp[i] = dp[i-1] + 2 + ((j - 1) >= 0 ? dp[j - 1] : 0);
                        
                        
                    }
                }
               
                maxLen = max(maxLen, dp[i]);
            } 
        }
        
        return maxLen;
    }
};

java:

class Solution {
    public int longestValidParentheses(String s) {
        int maxLen = 0;
        int n = s.length();
        int[] dp = new int[n];
        for(int i = 1; i < n; i++){
            if(s.charAt(i) == ')'){
                if(s.charAt(i-1) == '('){
                    dp[i] = (i - 2) >= 0 ? dp[i-2] + 2 : 2;
                    
                } else {
                    int j = i - dp[i-1] - 1;
                    
                    if(j >= 0 && s.charAt(j) == '('){
                       
                        
                        dp[i] = dp[i-1] + 2 + ((j - 1) >= 0 ? dp[j - 1] : 0);
                        
                        
                    }
                }
               
                maxLen = Math.max(maxLen, dp[i]);
            } 
        }
        
        return maxLen;
    }
}

python:
注意点:dp[i] = dp[i-1] + 2 + (dp[j - 1] if (j - 1) >= 0 else 0) 必须在后边加括号,否则它的意思为 if (j - 1) >= 0 dp[i] = dp[i-1] + 2 + (dp[j - 1] 否则dp[i] = 0

class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        dp = [0] * n
        maxLen = 0;
       
        for i in xrange(1, n):
            if s[i] == ')':
                if s[i-1] == '(':
    
                    dp[i] = dp[i-2] + 2 if (i - 2) >= 0 else 2
                    
                else:
                    j = i - dp[i-1] - 1
                    
                    if j >= 0 and s[j] == '(':
                       
                        
                        dp[i] = dp[i-1] + 2 + (dp[j - 1] if (j - 1) >= 0 else 0)
                       
                        
                        
                    
                
               
                maxLen = max(maxLen, dp[i])
             
        
        
        return maxLen;
        
        

解法三:两遍扫描法
这种方法不需要额外的空间
设置两个变量left和right,分别代表(和)的数量
首先先正向扫描,从左到右,分别记录(和)的数量,如果left = right 说明是有效字符串,记录它的数量left * 2,更新最大数量
如果)的数量大于(的数量,说明出现非法括号,(和)的数量置0
仅仅正向扫描还是不够的
如“()((())”有效括号为4,正向扫描只能得到2
首先先正向扫描,从左到右,分别记录(和)的数量,如果left = right 说明是有效字符串,记录它的数量left * 2,更新最大数量
如果(的数量大于)的数量,说明出现非法括号,(和)的数量置0
如“()((())”有效括号为4,经过正向反向扫描得到正确的答案4
C++:

class Solution {
public:
    int longestValidParentheses(string s) {
        int maxLen = 0;
        int n = s.size();
        int left = 0,right = 0;
        for(int i = 0; i < n; i++){
            if(s[i] == '('){
                left++;
            } else {
                right++;
            }
            if(left == right){
                maxLen = max(maxLen, 2 * right);
            } else if(right > left){
                left = right = 0;
            }
        }
        left = right = 0;
        for(int i = n-1; i >= 0; i--){
            if(s[i] == '('){
                left++;
            } else {
                right++;
            }
            if(left == right){
                maxLen = max(maxLen, 2 * right);
            } else if(left > right){
                left = right = 0;
            }
        }
        
        return maxLen;
    }
};

java:

class Solution {
    public int longestValidParentheses(String s) {
        int maxLen = 0;
        int n = s.length();
        int left = 0,right = 0;
        for(int i = 0; i < n; i++){
            if(s.charAt(i) == '('){
                left++;
            } else {
                right++;
            }
            if(left == right){
                maxLen = Math.max(maxLen, 2 * right);
            } else if(right > left){
                left = right = 0;
            }
        }
        left = right = 0;
        for(int i = n-1; i >= 0; i--){
            if(s.charAt(i) == '('){
                left++;
            } else {
                right++;
            }
            if(left == right){
                maxLen = Math.max(maxLen, 2 * right);
            } else if(left > right){
                left = right = 0;
            }
        }
        
        return maxLen;
    }
}

python:

class Solution(object):
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        maxLen, n , left , right = 0, len(s), 0, 0
       
        for c in s:
            if c == '(':
                left += 1
            else:
                right += 1
            
            if left == right:
                maxLen = max(maxLen, 2 * right)
            elif right > left:
                left = right = 0
            
        
        left = right = 0;
        for c in s[::-1]:
            if c == '(':
                left += 1
            else:
                right += 1
            
            if left == right:
                maxLen = max(maxLen, 2 * right)
            elif left > right:
                left = right = 0
        
        return maxLen;
                        
                        
                    
                
               
               
        
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值