Longest Valid Parentheses (H)
题目
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: 2
Explanation: The longest valid parentheses substring is "()"
题意
给定一个只包含左右括号的字符串,输出连续匹配括号对的最长长度。
思路
个人想到的方法是压栈法:建两个栈,一个par存括号字符,另一个index存括号字符对应的下标。用i遍历字符串,如果为'(',则同时压入两个栈;若为')',此时如果par为空,则压入par和index,如果par非空且栈顶元素为'(',说明配对成功,同时出栈par和index,而此时index的栈顶元素(非空时)代表的是当前最右边无法匹配的括号的下标,那么 i - index.peek() (index非空)/ i + 1 (index为空) 就代表了新增一对匹配括号对后更新的连续匹配长度,将之与max比较并更新max。
官方的压栈法解答只使用了一个栈,但整体思路是一样的。
左右扫描法:设两个计数器left和right,先从左向右扫描字符串,'('则left+1,')'则right+1,每扫描一个字符串,比较left和right,如果left < right,则将left和right重置,如果left == right,则更新max;同理再从右向左扫描,如果left > right,则将left和right重置,如果left == right,则更新max。
这是因为左右扫描,不能正确处理"( ) ( ( ( ) )"这种情况,而右左扫描可以;右左扫描不能正确处理"( ( ) ) ) ( )"这种情况,但左右扫描可以。
动态规划:dp数组记录以当前括号字符为结尾的最大有效长度,显而易见只有以')'为结尾才可能形成有效字符串,因此只有在当前字符为')'时才进行处理,共可能会有以下两种情况:
- s[i] == ')' && s[i - 1] == '(',这时很容易得到 \(dp[i] = dp[i - 2] + 2\);
- s[i] == ')' && s[i - 1] == ')',这种情况下,先找到以s[i - 1]为结尾的有效字符串开头的前一个字符c (当然如果dp[i - 1] == 0,就不需要找这个c了),如果c为'(',则与s[i]构成匹配括号对,同时还要考虑以c前一个字符c'为结尾的有效字符串的长度 (举个例子,"( ) ( ( ) )",最后一个')'为s[i]),最终得到 \(dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2]\)。
代码实现
Java
压栈法
class Solution {
public int longestValidParentheses(String s) {
int max = 0;
Deque par = new ArrayDeque<>();
Deque index = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
par.push(c);
index.push(i);
} else {
if (par.isEmpty() || par.peek() != '(') {
par.push(c);
index.push(i);
} else {
par.pop();
index.pop();
max = Math.max(max, index.isEmpty() ? i + 1 : i - index.peek());
}
}
}
return max;
}
}
class Solution {
public int longestValidParentheses(String s) {
int max = 0;
Deque stack = new ArrayDeque<>();
stack.push(-1);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
stack.push(i);
} else {
stack.pop();
// 出栈后若栈空,说明出栈的是不匹配的')',将当前')'压入栈
// 若栈非空,说明出栈的是匹配的'(',更新max
if (stack.isEmpty()) {
stack.push(i);
} else {
max = Math.max(max, i - stack.peek());
}
}
}
return max;
}
}
左右扫描法
class Solution {
public int longestValidParentheses(String s) {
int max = 0;
int left = 0, right = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
left++;
} else {
right++;
}
if (left == right) {
max = Math.max(max, left + right);
} else if (left < right) {
left = right = 0;
}
}
left = right = 0;
for (int i = s.length() - 1; i >= 0; i--) {
char c = s.charAt(i);
if (c == '(') {
left++;
} else {
right++;
}
if (left == right) {
max = Math.max(max, left + right);
} else if (left > right) {
left = right = 0;
}
}
return max;
}
}
动态规划
class Solution {
public int longestValidParentheses(String s) {
int max = 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 >= 0 ? dp[i - 2] + 2 : 2;
} else {
if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0);
}
}
}
}
for (int i = 0; i < s.length(); i++) {
max = Math.max(max, dp[i]);
}
return max;
}
}
JavaScript
压栈法
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function (s) {
let max = 0
let stack = []
for (let i = 0; i < s.length; i++) {
if (s[i] === '(' || stack.length === 0 || s[stack[stack.length - 1]] === ')') {
stack.push(i)
} else {
stack.pop()
max = Math.max(max, i - (stack.length === 0 ? -1 : stack[stack.length - 1]))
}
}
return max
}
左右扫描法
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function (s) {
return Math.max(scan(s.split(''), true), scan(s.split('').reverse(), false))
}
let scan = function (s, flag) {
let left = 0, right = 0
let max = 0
for (let p of s) {
if (p === '(') {
left++
} else {
right++
}
if (left === right) {
max = Math.max(max, left + right)
} else if (flag ? left < right : left > right) {
left = right = 0
}
}
return max
}
动态规划
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function (s) {
let max = 0
let dp = new Array(s.length).fill(0)
for (let i = 1; i < s.length; i++) {
if (s[i] === ')') {
if (s[i - 1] === '(') {
dp[i] = i > 1 ? dp[i - 2] + 2 : 2
} else if (i - dp[i - 1] > 0 && s[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
}