【数据结构与算法】动态规划解不同的子序列

本文介绍了如何使用动态规划解决LeetCode第115题,计算给定字符串s的所有子序列中与字符串t完全相同的子串数量。通过定义dp数组并列出递推公式,解决了字符串t的前i个字符在s的子序列中的匹配计数问题。
摘要由CSDN通过智能技术生成

问题描述

来源:LeetCode第115题

难度:困难
给定一个字符串s和一个字符串t,计算在s的子序列中t出现的个数。
字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置
所组成的新字符串。(例如,"ACE"是"ABCDE"的一个子序列,而"AEC"不是)
题目数据保证答案符合32位带符号整数范围。

示例 1:
输入:s = “ra b b b i t”, t = “ra b b i t”
输出:3
解释:
如下图所示, 有3种可以从s中得到"ra b b i t"的方案。
ra b bbi t
ra bbb i t
rabb b i t
示例 2:
输入:s = " b a b g b a g “, t = " b a g "
输出:5
解释:
如下图所示, 有5种可以从s中得到” b a g "的方案。
b abgb a g
b ab g b ag
ba b g ba g
b abg ba g
b a b gb a g
提示:
0<=s . length, t. length<=1000
s和t由英文字母组成

动态规划解决
这题说的是s的子序列中出现t的个数,翻译一下就是字符串s的所有子序列中,和字符
串t完全一样的有多少个。
我们定义dp[i][ j]表示t的前i个字符可以由s的前j个字符组成的个数(也可以说是字符
串s 的前j个字符组成的子序列中,和字符串t 的前i个字符组成的字符串一样的有多少
个)。
那么最终我们只需要求出dp[tLength][ sLength]即可(其中tLength和sLength分
别表示字符串t和s的长度)。
如果字符串t的第i个字符和字符串s的第j个字符一样,如下所示
在这里插入图片描述

如上图所示我们可以有两种选择。
如果字符串t的第i个字符和字符串s的第j个字符不一样,也就是说字符串s的第j个字符
不能匹配字符串t的第i个字符。那么我们只能计算字符串s的前j -1个字符构成的子序列
中包含字符串t的前i个字符组成的字符串的个数。
所以递推公式如下

for (int j = 1; j <= sLength; j++) {
if (t.charAt(i - 1) == s.charAt(j - 1)) {
//如果字符串t的第i个字符和s的第j个字符一样,
//那么有两种选择
dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
} else {
//如果字符串t的第i个字符和s的第j个字符不一样,
//我们只能用字符串s的前j-1个字符来计算他包含的数量
dp[i][j] = dp[i][j - 1];
}

动态规划的三个步骤就是定义状态,列出递推公式,找出边界条件。前面两步我们都完
成了,我们来看最后一个。因为空字符串" "是所有字符串的子集,所以当字符串t为空
的时候,dp[0][ j]=1;
我们来看下最终代码

public int numDistinct(String s, String t) {
//sLength和tLength分别是两个字符串的长度
int sLength = s.length();
int tLength = t.length();
int[][] dp = new int[tLength + 1][sLength + 1];
//base case 边界条件
for (int j = 0; j <= sLength; j++) {
dp[0][j] = 1;
}
for (int i = 1; i <= tLength; i++) {
for (int j = 1; j <= sLength; j++) {
//下面是递推公式
if (t.charAt(i - 1) == s.charAt(j - 1)) {
//如果字符串t的第i个字符和s的第j个字符一样,
//那么有两种选择
dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
} else {
//如果字符串t的第i个字符和s的第j个字符不一样,
//我们只能用字符串s的前j-1个字符来计算他包含的数量
dp[i][j] = dp[i][j - 1];
}
}
}
return dp[tLength][sLength];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Code_徐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值