32.最长有效括号

https://leetcode-cn.com/problems/longest-valid-parentheses/

题目描述

方法 1:滑动窗口

思路

  1. 首先最短的有效括号字符串就是一对括号 (),那我们可以先在字符串 s 中找到这样一对括号。

  2. 然后,把这对括号作为一个滑动窗口的中心,分别向左右两侧扩大滑动窗口,窗口内是有效括号。

  3. 当滑动窗口不能再扩大时,把当前窗口的左右边界记录下来,然后,从这个窗口的右边界开始,重复步骤 1 到 3,直到字符串遍历结束。

  4. 等等,还漏了一种情况。当我们在扩大滑动窗口的时候,如果碰到了另一个窗口的边界,那这两个窗口加起来也是一个有效括号字符串。所以,我们得把这两个窗口作为新的滑动窗口中心,然后向两侧扩大窗口。

  5. 因为我们是从左往右遍历字符串,所以窗口相碰的情况只有一种,就是当前窗口的左边界碰到了前一个窗口的右边界,我们只要判断这种情况就行。

图解

代码

JavaScript Code

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串的长度。

  • 空间复杂度:$O(n)$,n 为字符串的长度。

方法 2:动态规划

思路

我们可以用一个一维数组 dp 来记录 以当前坐标为结尾的有效括号字符串的长度是多少 这个状态。

关键是,怎么找到当前坐标的状态 dp[i]i 之前坐标的状态的依赖关系。

  • 如果当前坐标 i 是一个左括号 '(',很明显有效字符串不会以左括号为结尾,所以这个状态是 0;

  • 如果当前坐标 i 是一个右括号 ')',那么:

    • 如果它前一个 i - 1 是 '(',它们可以组成一对儿,那么 dp[i] 至少是 2

    • 如果它前一个 i - 1 是 ')',虽然它们不能成对儿,但是,')' 说明它可能是某个有效字符串的结尾,那我们就得检查这个坐标 i - 1 的状态了:

      • 如果 dp[i-1] 是 0,那就没戏了,dp[i] 也只能是 0 了

      • 如果 dp[i-1] > 0,那么,i 的前面有一段有效括号字符串,那只要判断这段字符串前面的那个字符是不是 ( 就好了,如果是,dp[i] = dp[i-1] + 2,如果不是,dp[i] = 0

    • 等等,还没有结束,如果到了这里,dp[i] 大于 0 的话,还有一种情况,跟滑动窗口解法里面的一样,它的左边可能还有一段紧挨着的有效括号字符串,所以我们得把这段字符串的长度也加到 dp[i] 中。

图解

代码

JavaScript Code

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串的长度。

  • 空间复杂度:$O(n)$,n 为字符串的长度。

方法 3:栈

思路

用一个栈来检查括号的有效性,用一个数组 valid 来记录匹配括号对的位置。

  • 栈的用法跟20.有效括号里的一样,不过入栈的不是 (,而是它们的下标。

  • 在遍历过程中,如果碰到 ),就从栈中弹出一个元素,这个元素就是 ) 对应的 ( 的下标。

  • 接着我们在 valid 中这两个下标对应的位置做个标识 1,说明这里找到了一对有效括号。

  • 等遍历结束之后,在 valid 中找到连续最长的 1 序列。

代码

JavaScript Code

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串的长度。

  • 空间复杂度:$O(n)$,n 为字符串的长度。

Last updated

Was this helpful?