问题:给定A[0,...,m-1],B[0,...,n-1],问B在A中出现几次(可以不连续)
例:
A = ['r','a','b','b','b','i','t']
B = ['r','a','b','i','t']
输出:3
问题分析:可以用类似于最长公共子串的思路。问B在A中出现的次数,考虑最后一个字符B[n-1]和A[m-1]
case1:如果B[n-1] = A[m-1],则考虑B[0,...,n-2]在A[0,...,m-2]出现多少次
case2:如果B[n-1] != A[m-1],则考虑B[0,...,n-1]在A[0,...,m-2]出现多少次
子问题:原问题:问B[0,...,n-1]在A[0,..,m-1]中出现的次数
现在变成B[0,...,n-2]在A[0,...,m-2]出现的次数和B[0,...,n-1]在A[0,...,m-2]出现的次数
设f[i][j]表示B的前j个字符B[0,...,j-1]在A的前i个字符A[0,...,i-1]出现的次数
则f[i][j] = f[i-1][j-1](B[j-1] = A[i-1]) + f[i-1][j]
case1 + case2
初始情况;
f[i][0] = 1,(i = 0,...,m)空串在字符串里出现的次数为1,
f[0][j] = 0,(j = 1,...,n)表示字符串在空串里出现的次数是0
计算顺序:
f[0][0]...f[0][n]
.
.
.
f[m][0]...f[m][n]
答案:f[m][n]
时间复杂度O(mn),空间复杂度O(mn),同样可以优化到O(n)
代码及注释如下:
def distinct_subs(A,B):
m ,n= len(A),len(B)
if m < n:
return 0
f = [[0 for i in range(n+1)] for j in range(m+1)]
#初始化
for i in range(m+1):
for j in range(n+1):
#f[i][0] = 1,(i = 0,...,m)
#f[0][j] = 0,(j = 1,...,n)
if j == 0:
f[i][j] = 1
continue
if i ==0 :
f[i][j] = 0
continue
#f[i][j] = f[i-1][j-1](B[j-1] = A[i-1]) + f[i-1][j]
f[i][j] = f[i-1][j]
if B[j-1] == A[i-1]:
f[i][j] += f[i-1][j-1]
return f[m][n]
A = ['r','a','b','b','b','i','t']
B = ['r','a','b','i','t']
print(distinct_subs(A,B))
#答案:3