这个题是要求不同子序列有几种组法,给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
示例 1:
输入:S = “rabbbit”, T = “rabbit”
输出:3
解释:
如下图所示, 有 3 种可以从 S 中得到 “rabbit” 的方案。
(上箭头符号 ^ 表示选取的字母)
rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^
解题思路:
-
这是一道非常经典的动态规划问题,一般遇到两个字符串的问题,很大可能都是动态规划,照常先画表格
-
考虑初始化dp数组
(1)如果s1,s2都为空,那么结果是一种,也就是说dp[0][0] = 1
(2)如果s2为空,那么结果s1中一定包含空字符串,也就是说dp[0][len(s2)] = 1
(3)如果s1为空,s2不为空,那么s1中一定不包含s2,也就是说第一列除了dp[0][0]位置都为0
-
填充第一行
当s1[0] = s2[0] = r时,r的组法一种,dp[1][1] = 1,后面与r都不同,所以都是1
-
找此方法写完
-
一边找矩阵规律,一边思考题意
找矩阵规律分为两种情况:
(1)s1==s2,相等时怎么变的,(另,相等时一般与dp[i-1][j-1]相关)
(2)s1 != s2,不等时怎么变的,(另,不相等时一般与dp[i][j-1],dp[i-1][j]相关,有时也会与dp[i-1][j-1]相关)
思考题意,相等时,可以不可考虑当前位,那么dp[i][j]就是由dp[i-1][j-1]转化而来的,考虑当前位,在有s2[j]时已经有n一种组成,而当前又相等,那么组成情况应该在多一个n种组成,那么规律就出来了
dp[i][j] = dp[i-1][j-1] + dp[i][j-1]
思考题意,不相等时,可以不考虑当前位,不要这一位已经又n种情况,因为当前位不等要了这一位应该还是n种,那么规律就出来了
dp[i][j] = dp[i][j-1] -
对比矩阵,发现规律没有问题,完成
提交代码:(动态规划,Runtime: 128 ms, faster than 84.21 % )
class Solution:
def numDistinct(self, s: str, t: str) -> int:
dp = [([0] * (len(s)+1)) for _ in range(len(t)+1)]
for _ in range(len(s) + 1):
dp[0][_] = 1
for i in range(len(t)):
for j in range(len(s)):
if t[i] == s[j]:
dp[i + 1][j + 1] = dp[i + 1][j] + dp[i][j]
else:
dp[i + 1][j + 1] = dp[i + 1][j]
return dp[-1][-1]