题目描述:
给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 10^9 + 7 取模。


提示:
1 <= s.length, t.length <= 1000
s 和 t 由英文字母组成
思路分析:
-
为什么可以用动态规划来解决这个题目呢?
最优子结构:问题可以分解为更小的子问题。例如,如果我们已经知道了 s 中前 i 个字符和 t 中前 j 个字符的子序列数,我们可以利用这个信息来推导 s 中前 i+1 个字符和 t 中前 j+1 个字符的子序列数。
重叠子问题:子问题的结果会被多次使用。比如,计算 s[0..i] 和 t[0..j] 的子序列数时,我们可能会多次计算相同的子问题,因此可以通过保存中间结果来避免重复计算。
-
DP五部曲
2.1 明确DP数组的含义
一般来说DP的含义就是题目要求的东西,本题要求S中出现的T的子序列的数量,那么DP的含义就应该往这上面靠。同时DP的核心意思是记录子问题的答案来解决后续问题,所以对应这个题目,我们需要不断遍历子序列,就是不同的序列长度,这是子问题和区别,所以DP数组自然就是定义为:
dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
i-1和j-1是为了方便遍历和初始化。
2.2递归函数
反正做法就是循环遍历所有元素的所有情况,那么遍历过程中就有两种情况:
1.当前两个元素相同
如果当前两个字符串中的元素相同,那么dp[i][j]的值就等于没有这两个字符的值+不使用s中最后一个元素的情况。即:dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]。比如bagg和bag
2.当前两个元素不相同
这时候就是不要被比较的元素的情况,即:dp[i][j] = dp[i - 1][j]。
注意一个问题,就是对比两个字符串的时候总是把一个字符串作为基准字符串,空字符永远是某个元素的子串,所以第一行的元素都是1.
点击查看代码
func numDistinct(s string, t string) int {
m,n:=len(t),len(s)
dp:=make([][]int,m+1)
for i:=range dp{
dp[i] = make([]int, n+1)
}
for j := 0; j < n+1; j++ {
dp[0][j] = 1
}
for i := 1; i < m+1; i++ {
for j := 1; j < n+1; j++ {
if t[i-1] == s[j-1] {
dp[i][j] = dp[i-1][j-1]+dp[i][j-1]
}else {
dp[i][j] = dp[i][j-1]
}
}
}
return dp[m][n]
}
浙公网安备 33010602011771号