leetCode-32: 最长有效括号

题目描述

给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例

示例 1:
输入:s = “(()”
输出:2
解释:最长有效括号子串是 “()”

示例 2:
输入:s = “)()())”
输出:4
解释:最长有效括号子串是 “()()”

示例 3:
输入:s = “”
输出:0

解题思路

步骤

(1)将字符串转换为 char 型数组;
(2)新开辟栈空间,用来存储括号的下标,栈底元素设置为-1;
(3)遍历数组,若当前元素为 ')' 且栈中元素数量大于1 且栈顶元素对应的数据为  '(',则将栈顶元素出栈;否则,将当前元素的下标入栈;
(4)遍历栈,计算相邻栈中元素的差值,取最大的,即为最终结果

代码展示

public class LongestValidParentheses {

    public static int longestValidParentheses(String s) {
        if (s.length() <= 1) {
            return 0;
        }
        char[] charArray = s.toCharArray();
        Stack<Integer> invalidParenthesesIndexStack = new Stack<Integer>();
        invalidParenthesesIndexStack.push(-1);
        for (int i = 0; i < charArray.length; i++) {
            // 如果是 ')', 并且栈顶元素对应的数据为 '(', 并且栈中至少有两个元素, 则将栈顶元素出栈
            if (charArray[i] == ')' && invalidParenthesesIndexStack.size() > 1 && charArray[invalidParenthesesIndexStack.peek()] == '(') {
                invalidParenthesesIndexStack.pop();
            } else {
                invalidParenthesesIndexStack.push(i);
            }
        }
        int result = 0;
        if (invalidParenthesesIndexStack.peek() != s.length() - 1) {
            result = s.length() - 1 - invalidParenthesesIndexStack.peek();
        }
        // 遍历栈
        if (invalidParenthesesIndexStack.size() == 1) {
            return s.length();
        }
        if (invalidParenthesesIndexStack.size() > 1) {
            for (int i = 1; i < invalidParenthesesIndexStack.size(); i++) {
                result = Math.max(result, invalidParenthesesIndexStack.get(i) - invalidParenthesesIndexStack.get(i - 1) - 1);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        String s = "(()())()";
        System.out.println("字符串为:" + s);
        int result = longestValidParentheses(s);
        System.out.println("最长有效括号为:" + result);
    }

}

图解

以字符串 “(()())()” 为例:
1.将字符串转换为 char 型数组,并新创建栈,栈底元素初始化为 -1,栈中存储的是数组中元素的下标;

 2.遍历数组 Array,处理栈 Stack 的谈栈与压栈

(1)i = 0 时,Array[i] == '(',直接进行压栈操作,此时栈 Stack 中有两个元素,-1 和 0;

(2)i = 1 时,Array[i] == '(',直接进行压栈操作,此时栈中有三个元素,-1、0 和 1;

(3)i = 2 时,Array[i] == ')',此时栈顶元素为 1,对应的数组中的元素为 '(',满足弹栈条件,所以将栈顶元素出栈,之后栈中元素为 -1 和 0。

(4)i = 3 时, Array[i] == '(',直接进行压栈操作,此时栈中有三个元素,-1、0 和 3;

 (5)i = 4 时,Array[i] == ')',此时栈顶元素为 3,对应的数组中的元素为 '(',满足弹栈条件,所以将栈顶元素出栈,之后栈中元素为 -1 和 0。

(6)i = 5 时,Array[i] == ')',此时栈顶元素为 0,对应的数组中的元素为 '(',满足弹栈条件,所以将栈顶元素出栈,之后栈中元素为 -1。

(7)i = 6 时, Array[i] == '(',直接进行压栈操作,此时栈中有两个元素,-1 和 6;

(7)i = 7 时, Array[i] == ')',此时栈顶元素为 6,对应的数组中的元素为 '(',满足弹栈条件,所以将栈顶元素出栈,之后栈中元素为 -1。

此时,遍历结束,栈中元素为 -1。我们可以看到,除 -1 外,栈中存储的元素其实就是原字符串中非法括号的下标。

3.遍历栈。

此时栈中元素为 -1,即栈初始化时的栈底元素。那么我们就认为,字符串中的括号都是有效的,于是直接返回字符串长度即可。

我们已经知道,栈中存储的元素即为无效括号在原字符串中的下标,那么就可以知道原字符串中有效括号的范围。以字符串 ")()()(()" 来说,遍历完数组之后,栈中元素为:-1、0、5。那么有效括号的范围即为[1,4],除此之外,也需要考虑到一种特殊情况,即下标 5 之后的括号都是有效的,所以需要在代码中对此种情况进行特殊处理。

还有一个疑问点便是:为什么初始化栈时需要设置栈底元素为 -1?

简单说来就是为了计算方便。比如对于字符串 "()()()(()()" 来说,遍历完数组之后,栈中存储元素为 -1、6。最终得到的最长有效括号的长度为 Max(6, -1) - 1 = 6。如果不初始化栈底元素为 -1 的话,那么遍历完数组之后栈中只有一个元素 6,此时就需要去与 0 和原字符串长度做一系列的比较。当然,也不是非要初始化栈底元素为 -1,如果可以理清其中的关系的话,就没必要去初始化栈底元素了。

当然,最终在遍历栈的时候,可以在遍历之前将站定元素与字符串长度进行比较,如果栈顶元素不等于字符串长度 - 1,可以考虑先计算一下最终要返回的结果 result,也可以直接将字符串长度 - 1 的值进行压栈,使其参与遍历栈的操作。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值