括号匹配问题

最长有效括号-栈

今天我们来看一道最长有效括号的题目,题目描述如下:
在这里插入图片描述

这里只列举了最常见的用例,其实还有一些复杂的用例,我们列举一下符合的情况:

  • (()())
  • (()(()))()
  • ()()
  • ()

这道题要求算出最长的有效括号子串,我们使用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这个时间我估计是根据他的时间复杂度判定逻辑估算出来的一个值。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安静的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值