0と1に還元され
689 words
3 minutes
最长有效括号
Cover Image Source: Source
题目链接:32. 最长有效括号
误入歧途
本题一眼顶真,鉴定为动态规划,关键在于怎么动态规划。
一开始我的想法比较暴力,用一个二维数组f[n][n+1]来保存状态(实际用向量来实现)。其中f[i][j]表示从范围内的连续子串是否满足括号匹配规则( 时表示空串,此时f[i][j]值为true)。
对于一个合法的子串,一定以')'结尾。故合法子串可表示为 ,A和B均可为空串。对于每一个满足上式的子串,只需遍历所有的有序对 即可判断是否是合法子串。转移方程如下:
代码如下
class Solution {public: int longestValidParentheses(string s) { int n = s.length(); int maxn = 0; vector<vector<int>> f(n, vector<int>(n + 1, 0)); for (int i = 0; i < n; ++i) f[i][0] = 1; for (int j = 2; j <= n; j+=2) for (int i = 0; i + j <= n; ++i) if (s[i + j - 1] == ')') for (int k = 0; k < j - 1; k+=2) if (s[i + k] == '(' && f[i][k] && f[i + k + 1][j - k - 2]) { f[i][j] = true; maxn = j; break; } return maxn; }};时间复杂度为。很不幸的是这个方法超时了。
另起炉灶
重新思考后,我尝试了新的算法,将时间复杂度降到了 。新的算法用一维数组dp[n+1]保存状态。其中dp[i]表示所有以第 个字符为结尾的合法子串中最长的子串的第一个字符的下标,即下标在 中的所有字符组成一个合法子串且该子串无法向左扩充为新的子串。如果没有这样的子串,则。
沿用之前的思路,合法子串可表示为。当s[i-1]为')'时,通过dp[i-1]可获取,若s[dp[i-1]-1]为'(',则通过dp[dp[i-1]-1]可获取。转移方程如下:
代码如下:
class Solution {public: int longestValidParentheses(string s) { int n = s.length(); int maxn = 0; vector<int> dp(n + 1, 0); // dp[i]表示所有以第i-1个字符为结尾的合法子串中最长的子串的第一个字符的下标 for (int i = 0; i <= n; ++i) dp[i] = i; for (int i = 2; i <= n; ++i) { if (s[i - 1] != ')') continue; if (dp[i - 1] == 0 || s[dp[i - 1] - 1] != '(') continue; dp[i] = dp[dp[i - 1] - 1]; maxn = max(i - dp[i], maxn); } return maxn; }};评测结果
执行用时:4 ms, 在所有 C++ 提交中击败了77.37%的用户
内存消耗:7.2 MB, 在所有 C++ 提交中击败了21.63%的用户
通过测试用例:231 / 231