lecode-32 最长有效括号-动态规划
书接上回,前面我们用了一种暴力解法,最后时间复杂度为O(n2),这次我们使用动态规划和栈的思路来得出一种更为简便高效的算法。为了防止有些朋友没看过上一篇,我再贴一遍题目。
对于栈的操作如下:
- 遇到
(
进行压栈操作 - 遇到
)
进行出栈操作
我们使用dp[i]表示以s[i]结尾的最长有效子串,如果s[i]=(
那么dp[i]等于0;
那么如果s[i]=)
呢,这时候进行的是出栈操作,出栈意味着这里至少有一对括号,那么s[i]前面是什么情况呢,有两种情况:
- 这对括号中还有其他括号,比如:
(())
,那么对于最后一个右括号出栈的时候最长子串sub_dp=dp[i-1] +2 - 这对括号中没有其他括号,比如:
()
,这里其实可以直接等于2,为了统一公式,最长子串sub_dp=dp[i-1]+2,因为dp[i-1]也就是左括号的值恒为0
这样我们就完成了一个局部子串的长度计算,那么这个子串前面是什么情况,会不会也有连续的有效括号,这里我以中划线区分前后,比如:
()|()
()|(())
因为我们已经知道了后面这一块子串的有效字符长度,那么只需要偏移回去加上中划线前面部分的dp即可,公式为:dp[i] = sub_dp + dp[i - sub_dp],由此我们已经推导出了动态规划的状态转移公式,可以写代码啦。这里在总结一下:
代码实现如下:
#include<stdio.h>
#include<string.h>
int longestValidParentheses(char* s) {
int len = strlen(s);
int i = 0, count = 0;
int dp[100];
int sub_dp = 0;
int max_dp = 0;
memset(dp, sizeof(dp), 0);
for (i = 0; i < len; i++)
{
if (*(s+i) == '(')
{
dp[i] = 0;
count++;
}else
{
if (count==0)
{
dp[i] = 0;
}else
{
count --;
dp[i] = dp[i-1] + 2;
if ((i - dp[i]) >= 0)
dp[i] = dp[i] + dp[i - dp[i]];
}
}
if (dp[i] > max_dp)
max_dp = dp[i];
}
return max_dp;
}
int main(){
char s[] = ")()()(((())())(";
printf("result len %d\n", longestValidParentheses(s));
return 0;
}
lecode通过截图,这次时间复杂度变成了O(n)
``
lecode通过截图,这次时间复杂度变成了O(n)