LeetCode115不同的子序列

问题描述

给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。

一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE""ABCDE" 的一个子序列,而 "AEC" 不是)

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入: S = "rabbbit", T = "rabbit"
输出: 3
解释:

如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案。
(上箭头符号 ^ 表示选取的字母)

rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

示例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输入: S = "babgbag", T = "bag"
输出: 5
解释:

如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案。
(上箭头符号 ^ 表示选取的字母)

babgbag
^^ ^
babgbag
^^ ^
babgbag
^ ^^
babgbag
^ ^^
babgbag
^^^

解题思路

本题也是字符串匹配问题,与刚刚做过的 第97题 的解题思路很相似。

这类问题,考虑使用一个二维动态dp数组进行动态规划求解。

二维动态数组的使用中,一般也会有几个步骤:

  1. 初始化数组
  2. 初始化第一列或者是第一行
  3. 计算DP数组中的值

先看图:

行表示子序列T,列表示父序列S,使用T来匹配S中的字符。

当匹配到的字符的位置为 matrix[i][j] 时,则继续匹配时,不能再选当前列之前的字符了,所以在下一行中,只能从 j+1 列开始匹配。

然后整理以上的规则,计算每个元素的值。

先初始化第一行与第一列,分析可得,第一行中,为 T 的位置的值都可以赋为1,第一列中的非第一行的元素的值,都应该为0。

根据上面分析的计算规律可得,对矩阵中的某个位置 matrix[i][j] 其值为 matrix[i-1][0:j]的和。计算结果如下图所示:

最终我们所求的结果值为:最后一行的 sum()

代码实现

Github Python3 代码实现

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution:
def numDistinct(self, s, t):
"""
:type s: str
:type t: str
:rtype: int
"""
col = len(s)
row = len(t)

if row > col:
return 0

matrix = []

for i in range(row):
matrix.append([0] * col)

# 初始化矩阵
for i in range(row):
for j in range(col):
if t[i] == s[j]:
matrix[i][j] = "X"

# 初始化第一行
for j in range(col):
if matrix[0][j] == "X":
matrix[0][j] = 1

# 初始化第一列
for i in range(row):
if matrix[i][0] == "X":
matrix[i][0] = 0

# 计算矩阵中的值
for i in range(1, row):
for j in range(1, col):
if matrix[i][j] == "X":
matrix[i][j] = sum(matrix[i - 1][0:j])

return sum(matrix[row-1])