题目:
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
方法一:暴力法
思路:
1、对于给定字符串中每种可能的非空偶数长度子字符串,判断其是否有效
2、如果有效,更新最大长度
时间复杂度:O(n^3)
空间复杂度:O(n)
var longestValidParentheses = function(s) {
let max = 0;
if(!s) return 0;
for(let i = 0, len = s.length; i < len; i++){
for(let j = i + 2; j <= len; j += 2){
let val = s.substring(i, j);
if(isValid(val) && val.length > max)
max = val.length;
}
}
return max;
};
var isValid = function(s){
let stack = [];
for(let i = 0, len = s.length; i < len; i++){
if(s[i] === '(')
stack.push(1)
else{
if(!stack.length)
return false;
else
stack.pop()
}
}
return !stack.length
}
方法二:动态规划
思路:
有效的子字符串一定以 ‘)’ 结尾,在这种情况下
1、如果s[i - 1] === '(' && s[i] === ')',则dp[i] = dp[i - 2] + 2
2、如果s[i - 1] === ')' && s[i] === ')'
(1)如果s[i - dp[i - 1] - 1] === '(', 即如果Sub代表i-1位置上的最长有效括号,s[i - dp[i - 1] - 1] 则代表,在sub之前一个位置上的字符,如果该字符是'(',则
dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2];
dp[i - dp[i - 1] - 2]代表Sub子串之前的最长有效括号长度
时间复杂度:O(n)
空间复杂度:O(n)
var longestValidParentheses = function(s) {
let max = 0,
len = s.length;
let dp = new Array(len).fill(0);
for(let i = 1; i < len; i++){
if(s[i] === ')'){
if(s[i - 1] === '('){
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2
}else if(i - dp[i - 1] - 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;
};
方法三:栈
思路:
使用栈将配对的括号消除,栈中剩余的便是不能消除的,从中计算有效括号的最大长度,为了方便计算,添加哨兵;
时间复杂度:O(n)
空间复杂度:O(n)
var longestValidParentheses = function(s) {
let max = 0,
len = s.length;
let stack = [-1];
for(let i = 0; i < len; i++){
if(s[i] === '('){
stack.push(i)
}else{
stack.pop();
if(!stack.length){
stack.push(i)
}else{
max = Math.max(max, i - stack[stack.length - 1])
}
}
}
return max;
};
方法四:双指针
思路:
1、定义两个指针left,right。
2、遇到'(',left++;遇到')',right++
3、如果left === right,更新最大值
4、如果right > left,left = right = 0
5、从右到左反方向遍历
时间复杂度:O(n)
空间复杂度:O(1)
var longestValidParentheses = function(s) {
let max = 0, left = 0, right = 0, len = s.length;
for(let i = 0; i < len; i++){
if(s[i] === '('){
left ++;
}else{
right ++;
}
if(left === right){
max = Math.max(max, right * 2)
}else if(right > left){
left = 0;
right = 0;
}
}
if(max === len) return max;
left = right = 0;
for(let i = len - 1; i >= 0; i--){
if(s[i] === '('){
left ++;
}else{
right ++;
}
if(left === right){
max = Math.max(max, right * 2)
}else if(left > right){
left = 0;
right = 0;
}
}
return max;
};