最长有效括号-栈
今天我们来看一道最长有效括号的题目,题目描述如下:
这里只列举了最常见的用例,其实还有一些复杂的用例,我们列举一下符合的情况:
- (()())
- (()(()))()
- ()()
- ()
这道题要求算出最长的有效括号子串,我们使用dp[i]表示从字符串第i个位置开始最长的有效子串的长度,例如)()()
- dp[0] = 0
- dp[1] = 4
- dp[2] = 0
- dp[3] = 2
- dp[4] = 0
只要求解出所有位置的最长子串那么我们可以知道最长的有效括号是dp[1],于下标1-3,即()()
思考一个问题,我们需要求出每个位置的子串长度吗?
答案是不需要,比如上面我们知道dp[1] = 4,那么从1到3这之间的dp[i]一定小于4,我们可以跳过中间的dp[2],dp[3]直接从dp[4]开始计算。
最后只剩一个问题,怎么求最长的有效子串呢?有效的括号子串有如下特点:
- 总是以
(
开始 (
和)
总是成对出现,既左括号的数量要等于右括号
所以dp[i]的计算方式如下:
这样你就可以计算出每个dp[i]的值了,只需要在计算过程中记住最大值的dp[i]的下标就可以知道最长有效子串的起始位置和终止位置了。
C语言代码如下:
#include<stdio.h>
int cal_dp(char *s)
{
char *tmp = s;
int count = 1;
if (*(s) == '\0' || *(s) == ')')
{
return 0;
}
for (tmp = s + 1; *tmp != '\0'; tmp++)
{
if (*(tmp) == ')')
{
count--;
}else{
count++;
}
if (count <= 0)
{
break;
}
}
if (count == 0)
{
int len = tmp - s + 1;
return len + cal_dp(s+len) ;
}
return 0;
}
int longestValidParentheses(char* s) {
char *tmp;
int i = 0;
int max_len = 0;
//printf("%s\n", s);
for (tmp = s; *tmp != '\0';)
{
int len = cal_dp(tmp);
//printf("index %d, len %d\n", i, len);
if (len > max_len)
{
max_len = len;
}
if (len)
{
tmp = tmp + len;
}else{
tmp++;
}
i=i+len;
}
return max_len;
}
int main(){
char s[] = "(())())";
printf("result len %d\n", longestValidParentheses(s));
return 0;
}
lecode通过截图,我感觉lecode这个时间计算很不准,栈的时间复杂度也是O(n),为什么就比动态规划慢这么多。
看了下他的时间复杂度分析,居然是O(n2),我估计他是看到我有两重循环就判定时间复杂度为n2,但是在第一层for循环有
tmp = tmp + len;
这句话,保证两个for循环不会有交集,实际复杂度为O(n),所以loceode这个时间我估计是根据他的时间复杂度判定逻辑估算出来的一个值。