题目介绍
力扣32题:leetcode-cn.com/problems/lo…
动态规划
1.定义dp数组
首先,我们定义一个 dp
数组,其中第 i
个元素表示以下标为 i
的字符结尾的最长有效子字符串的长度。
2.确定状态:
对于最优的策略,一定有最后一个元素 s[i]
.
所以,我们先看第 i
个位置,这个位置的元素s[i]
可能有如下两种情况:
-
s[i] == '(':这时,
s[i]
无法和其之前的元素组成有效的括号对,所以,dp[i] = 0。 -
s[i] == ')':这时,需要看其前面对元素来判断是否有有效括号对。
-
情况1:s[i - 1] == '(' ,即
s[i]
和s[i−1]
组成一对有效括号,有效括号长度新增长度2,i
位置对最长有效括号长度为 其之前2个位置的最长括号长度加上当前位置新增的2,我们无需知道i−2
位置对字符是否可以组成有效括号对。那么有:dp[i] = dp[i - 2] + 2
-
情况2:s[i - 1] == ')',这种情况下,如果前面有和
s[i]
组成有效括号对的字符,即形如( (....) )((....)),这样的话,就要求s[i - 1]
位置必然是有效的括号对,否则s[i]
无法和前面对字符组成有效括号对。这时,我们只需要找到和s[i]
配对对位置,并判断其是否是(
即可。和其配对对位置为:i - dp[i - 1] - 1
,如果:s[i - dp[i - 1] - 1] == '(' ,有效括号长度新增长度2,i
位置对最长有效括号长度为i-1
位置的最长括号长度加上当前位置新增的2,那么有:dp[i] = dp[i - 1] + 2
-
值得注意的是,i - dp[i - 1] - 1
和 i
组成了有效括号对,这将是一段独立的有效括号序列,如果之前的子序列是形如 (...)(...) 这种序列,那么当前位置的最长有效括号长度还需要加上这一段。所以:dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2
举个例子:)()(())
,此时i = 6
,dp[i - 1] = dp[5] = 2
,i - dp[i - 1] - 1 = 3
,i = 3
的位置刚好是'(',此时dp[6] = dp[5] + 2 = 4 ?
,但这是不正确的,因为最左边还有一对括号!!!,所以:dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2
3. 状态转移方程
if s[i] == '(' :
dp[i] = 0
if s[i] == ')' :
if s[i - 1] == '(' :
dp[i] = dp[i - 2] + 2 #要保证i - 2 >= 0
if s[i - 1] == ')' and s[i - dp[i - 1] - 1] == '(' :
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 #要保证i - dp[i - 1] - 2 >= 0
代码如下:
class Solution {
public int longestValidParentheses(String s) {
int n = s.length();
int[] dp = new int[n];//dp是以i处括号结尾的有效括号长度
int max_len = 0;
//i从1开始,一个是单括号无效,另一个是防i - 1索引越界
for(int i = 1; i < n; i++) {
if(s.charAt(i) == ')') { //遇见右括号才开始判断
if(s.charAt(i - 1) == '(') { //上一个是左括号
if(i < 2) { //开头处
dp[i] = 2;
} else { //非开头处
dp[i] = dp[i - 2] + 2;
}
}
else { //上一个也是右括号
if(dp[i - 1] > 0) {//上一个括号是有效括号
//pre_left为i处右括号对应左括号下标,推导:(i-1)-dp[i-1]+1 - 1
int pre_left = i - dp[i - 1] - 1;
if(pre_left >= 0 && s.charAt(pre_left) == '(') {//左括号存在且为左括号(滑稽)
dp[i] = dp[i - 1] + 2;
//左括号前还可能存在有效括号
if(pre_left - 1 > 0) {
dp[i] = dp[i] + dp[pre_left - 1];
}
}
}
}
}
max_len = Math.max(max_len, dp[i]);
}
return max_len;
}
}
复杂度计算:
-
时间复杂度: 遍历了一遍字符串,所以时间复杂度是:O(N)
-
空间复杂度:需要和字符串长度相同的数组保存每个位置的最长有效括号长度,所以空间复杂度是:O(N)