32 最长有效括号(递归、栈)

1. 问题描述:

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

示例 1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"

示例 2:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

提示:

0 <= s.length <= 3 * 10 ^ 4
s[i] 为 '(' 或 ')'

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-valid-parentheses/

2. 思路分析:

① 在一开始的时候感觉题目好简单,使用栈进行括号的匹配不就好了么,但是真正使用栈的时候发现不是这样的,比实际情况复杂得多因为当发现是 ( 的时候将其进栈,为 ) 的时候出栈,比如像这种情况是没有考虑全的()((),实际上它要求的是整个匹配的最长括号,所以不能够使用上面的思路进行匹配,后面的时候想到使用递归来操作,但是发现也是考虑不全,但是吧遇到这样的问题想到使用递归来解决是一个比较重要的思路,因为这样可以锻炼自己使用递归解决问题的一些能力,我一开始是想到对截取的字符串与截取后剩下的字符串进行递归将两部分进行累加再与历史最大值进行比较来决定是否更新最大值,但是我忽略了一个很重要的地方就是有效的括号是一个整体,递归求解出左右括号的最大值并不一定是有效的,也就是并不是一个整体,后面在LeetCode上发现一个递归写得不错的代码,可以借鉴一下,想一下怎么样处理其中细节对于递归的理解也是很有帮助的

② 他是在递归的时候先对传进来的字符串进行无用括号的消除,当发现字符串的最后边是(的时候这个时候这个左括号肯定是没有用的,直接去掉,当发现字符串的一开始的时候出现)的时候也是没有用的,直接删除掉,当处理掉这些没有用的括号之后,对字符串进行检查看一下是否符合括号匹配规则,假如不匹配肯定是在字符串的中间出现了不符合的括号匹配,所以分为两部分进行递归,一部分是字符串开始到字符串的倒数第一个字符结束,另外一部分是从字符串的开始到字符串末尾结束,因为匹配的最大值肯定是出现在这两种情况中的一种,到递归结束的时候肯定会找到匹配的最大值的,这个思路在递归的时候是以整体为主的所以是正确的,这个思路还是很好的,可以理解一下

③ 还有一种比较好理解的方法是使用栈,在官方提供的代码中很巧妙,而且很容易看得思路是怎么样的,主要是在匹配的时候将括号对应的下表进栈和对比从而求解出最长的有效匹配括号数目

3. 代码如下:

递归代码:

class Solution {
    public boolean check(String t) {
        int len = t.length();
        if(len==0) return true;
        if(len==1) return false;
        Stack<Character> s = new Stack<>();
        s.push(t.charAt(0));
        for(int i=1;i<t.length();i++) {
            if(s.empty() && t.charAt(i)==')') return false;
            else if(t.charAt(i)=='(') s.push('(');
            else if(t.charAt(i)==')' && s.peek()=='(') s.pop();
        }
        return s.empty();
    }
    public int longestValidParentheses(String s) {
        // 预处理
        int len = s.length();
        while(len>1 && s.charAt(0) == ')') {
            s=s.substring(1);
            len = s.length();
        }
        len = s.length();
        while(len>1 && s.charAt(len-1)=='(') {
            s=s.substring(0,len-1);
            len = s.length();
        }
        if(len==0 || len==1) return 0;

        // recursion
        if(check(s)) {
            return len;
        } else {
            return Math.max(longestValidParentheses(s.substring(1)),longestValidParentheses(s.substring(0,len-1)));
        }
    }
}

栈的代码:

java:

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;
    }
}

python:

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        res = 0
        stack = [-1]
        for i in range(len(s)):
            if s[i] == "(":
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    stack.append(i)
                else:
                    res = max(res, i - stack[-1])
        return res

go:

package main

import "fmt"

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func longestValidParentheses(s string) int {
	stack := []int{-1}
	res := 0
	for i := 0; i < len(s); i++ {
		if s[i] == '(' {
			stack = append(stack, i)
		} else {
			stack = stack[:len(stack)-1]
			if len(stack) == 0 {
				stack = append(stack, i)
			} else {
				res = max(res, i-stack[len(stack)-1])
			}
		}
	}
	return res
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值