题目
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)
题目数据保证答案符合 32 位带符号整数范围。
示例 1:
输入:s = "rabbbit", t = "rabbit"输出:3解释:如下图所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。(上箭头符号 ^ 表示选取的字母)rabbbit^^^^ ^^rabbbit^^ ^^^^rabbbit^^^ ^^^
示例 2:
输入:s = "babgbag", t = "bag"输出:5解释:如下图所示, 有 5 种可以从 s 中得到 "bag" 的方案。(上箭头符号 ^ 表示选取的字母)babgbag^^ ^babgbag^^ ^babgbag^ ^^babgbag^ ^^babgbag^^^
提示:
0 <= s.length, t.length <= 1000s和t由英文字母组成
题解
首先我们可以从 s中除去不在 t 中的字符,例如 s = "aabbcc", t = "ab",那我们把字符 c 删除是不影响结果的。
然后就是进行动态规划,假设 t[0] 在 s 中出现的位置为 i1,i2,...,im,那么有f(s,t) = f(s[i1+1:],t[1:]) + f(s[i2+1:],t[1:]) +...+ f(s[im+1:],t[1:])
举个很简单的例子:
f(cbabgbag,bag)
=f(babgbag,bag)
=f(abgbag,ag) + f(gbag,ag) + f(ag,ag)
=f(abgag,ag) + 1 + 1
=f(bgag,g) + f(g,g) + 2
=f(gg,g) + 1 + 2
=2 + 3
=5
那么代码就很容易写出来了:
from functools import lru_cache
def clr(s, t):
return "".join([c for c in s if c in t])
class Solution:
@lru_cache(maxsize=None)
def f(self, s, t):
count = 0
if len(s) < len(t):
return 0
if len(t) == 1:
return len(s)
for i in range(len(s)):
if s[i] == t[0]:
count += self.f(clr(s[i+1:], t[1:]), t[1:])
return count
def numDistinct(self, s: str, t: str) -> int:
S = clr(s, t)
return self.f(S, t)
官方题解
官方题解是这样写状态转移方程的:f(s,t) = f(s[i+1:],t[1:]) + f(s[i+1:],t)
那么计算方式就变成了这样:
f(cbabgbag,bag)
=f(babgbag,bag)
=f(abgbag,ag) + f(abgbag,bag)
=f(abgag,ag) + f(abgbag,bag)
=( f(bgag,g) + f(bgag,ag) ) + ( f(gbag,ag) + f(gbag,bag) )
=2 + 1 + 1 + 1
=5
循环程序如下:
class Solution:
def numDistinct(self, s: str, t: str) -> int:
m, n = len(s), len(t)
if m < n:
return 0
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][n] = 1
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
if s[i] == t[j]:
dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j]
else:
dp[i][j] = dp[i + 1][j]
return dp[0][0]
如果按这种思路写的话,搜索形式如下:
from functools import lru_cache
def clr(s, t):
return "".join([c for c in s if c in t])
class Solution:
@lru_cache(maxsize=None)
def f(self, s, t):
if len(s) < len(t):
return 0
if len(t) == 1:
return len(s)
for i in range(len(s)):
if s[i] == t[0]:
return self.f(clr(s[i+1:], t[1:]), t[1:])+self.f(s[i+1:], t)
return 0
def numDistinct(self, s: str, t: str) -> int:
S = clr(s, t)
return self.f(S, t)
不知道为什么速度快了很多。。。按理说我的那个应该更快才对
