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: 4
Explanation: The longest valid parentheses substring is"()()"
思路
尝试遍历判断所有组合结果超时,想到了用dp来解这题却不知道怎么来建模,还是经验少了。
看了下解答,有多种解法,首先是dp。看了之后发现为什么自己的dp总是建不起来了,首先是确定一维的dp还是二维的dp,这题的变量有两个,一个是字符串的长度,还有就是最优解也就是最长合法parentheses substring的长度,那么用一维的dp数组dp[i]即可。接下来确定的是dp[i],中索引的 i 具体指的是什么,在考虑这步的时候我没有想清楚,与其说 i 具体指什么倒不如说我们要赋给 i 的意义是什么,我原来的想法是 i 代表从0到i的字串,这样来代表子问题,比如dp[5]表示的是从索引0到5的字串中最长合法 parentheses substring 的长度,dp[10] 表示从索引0到10的字串中最长合法 parentheses substring 的长度等。然后依次去探究递推公式时(问题与其相邻子问题的关系)却发现很不好找,因为
假如在 i 位置和 i-1 位置上的 字符是 ( 和 ),构成一对合法,但是还是确定不了 dp[i] 和 dp[i-2] 的关系,因为确定不了dp[i-2] 中的合法字符是不是在末尾 i-2 处终结的,如果是的话则dp[i]=dp[i-2]+2,否则不能确定判断是否加2。
上面的dp建模思路之所以不正确是因为建模没有清楚问题,或者说是限定问题,也可以说是建模对于问题的描述存在不清楚,不明确的地方。比如对于 dp[i] 虽然可以由此知道子串的最长合法字串的长度,但是由于这题是括号匹配,故子串中括号字符串出现的位置是很重要的,而dp[i]虽然可以确定 子问题的最优解,子问题中字符串的长度这两个变化的要素,但是却确定不了合法括号字符串在字串中出现的位置,所以导致实际解题时思路异常困难,因为本身的模型就有问题。
正确的 dp[i] 建模是这样的,值肯定是最长合法括号字符串的长度,而这个 i 代表的是以i位置为结束的最长合法字串,即dp[5]表示的是索引0到5的字符串中以索引5(末尾)为结束的最长的合法字串的长度。这样便能很方便的确定问题与相邻子问题之间的数学关系。
第二个可能有点难理解,因为 dp[i] 表示的是以索引 i 处为结束的最长合法字串的长度,那么它前一个字符的位置便是 i - dp[i]-1, 如果这个位置 是 ( 那么可能和新加入的 ) 构成合法,因为这个 ( 之前的字符串也可能是合法的,所以要在一起算。
只考虑以上的情况是因为如果以(( 或者)( 的话,以 ( 在末位置结束的肯定是非法,dp数组的是0.
代码
public class Solution {
public int longestValidParentheses(String s) {
int maxans = 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 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
maxans = Math.max(maxans, dp[i]);
}
}
return maxans;
}
}
剩下的方式有两种,Using Stack 和 Without extra space: https://leetcode.com/problems/longest-valid-parentheses/solution/