算法设计与分析入门篇----动态规划 2

正在网易云课堂学习王宏志老师的算法设计与分析入门篇课程视频,将学习中的作业问题发上来与大家一同讨论。这篇是对第四周的作业第二题个人的一些思路,希望与大家一同学习。

2括号子序列 - A(10分)

题目内容:
一段括号序列被称为平衡的,如果对于任意前缀,左括号的数目都不小于右括号。
给定一段括号序列,问有多少括号子序列是平衡的。(内容相同但位置不同的算两种。)

输入格式:
多组测试数据,每组测试数据包含一行一个括号序列,括号序列的长度 <= 100。

输出格式:
输出一行表示答案模 10^9 + 7 后的结果。

输入样例:
(()())
()()

输出样例:
18
4

Hint:
样例一:
()__
(_)_
(__)
()__
(_)_
(__)
_()_
_(_)

()()
()()
()()
()()
((__))
(())
(()__)
(__())
(())

(()())

时间限制:2000ms内存限制:128000kb

做了这道题感觉自己对动态规划根本就不了解,先是想了一个时间复杂度为2^n的方法,通过记录每左括号后面的有括号个数,计算求解。
思路与代码结果都有问题,时间也超了。

问大四学长的思路:
定义dp[i][j][k]
表示当前我要处理字符串中第i个字符,
并且前面已经取了j个左括号和k个右括号。
由于题意要满足任意前缀,左括号的数目都不小于右括号
所以这里限定j>=k。
最终答案就是把所有dp[n][i][i]累加起来,这里i代表左括号个数
初始状态dp[0][0][0]=1,表示空串。
那么当前处理第i个字符
一种是忽略这个字符,dp[i+1][j][k] += dp[i][j][k]
一种是选择这个字符,那么就要判断这个字符是左还是右。
如果是左,直接累加,dp[i+1][j+1][k] += dp[i][j][k]
否则要先看如果加了这个右括号,会不会违反j>=k的规则,不违反则dp[i+1][j][k+1] += dp[i][j][k],违反就不管了

自己想了一下,大概有点明白。但第二天仔细研究,用递归做的话,时间复杂度也是2^n。
递归方程是 T(n) = 2*T(n-1) + o1;
用公式没求明白,但展开看的话还是很明显的
T(n) = 2 * T(n-1) + o1
= 2^2 * T(n-2) + ( 2 + 1) * o1
…….
= 2^(n-1)T(1) + (2^(n-2) + ……+ 2 + 1) o1 = o2^n

后来发现用循环来做时间复杂度仅为n^3。

代码如下:

int mo = 1000000007;
long a[101][101][101];
void jisuan(char*p, int n) {
    for (int i = 0; i < n; i++){
        for (int j = 0; j <= i; j++){
            for (int k = 0; k <= j; k++){
                if (a[i][j][k] == 0)
                    break;
                a[i + 1][j][k] = (a[i][j][k] + a[i + 1][j][k]) % mo;
                if (p[i] == '('){
                    a[i + 1][j + 1][k] = (a[i][j][k] + a[i + 1][j + 1][k]) % mo;
                }
                else
                    if (j > k){
                        a[i + 1][j][k + 1] = (a[i][j][k] + a[i + 1][j][k + 1]) % mo;
                    }
            }
        }
    }
}
//要注意这次是多组输入,对于每次输入要重新初始化。
void chushihua(int n){
    for (int i = 0; i <= n; i++){
        for (int j = 0; j <= i; j++){
            for (int k = 0; k <= j; k++){
                a[i][j][k] = 0;
            }
        }
    }
    a[0][0][0] = 1;
}

最终结果就是所有a[n][i][i]的和,n为字符个数,i从1到n/2。因为n个字符,平衡的子序列字符数小于等于n,其中左括号右括号相等,所以i<=n/2即可。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值