题目:原题链接(困难)
标签:字符串、动态规划、动态规划-状态表格
解法 | 时间复杂度 | 空间复杂度 | 执行用时 |
Ans 1 (Python) | O(M×N×C) : 其中C为状态最高出现频数 | O(Max(M,N)×C): 其中C为状态最高出现频数 | 超出时间限制 |
Ans 2 (Python) | O(M×N) | O(M×N) | 180ms (30.61%) |
Ans 3 (Python) | O(M+N×C) : 其中C为字符在t中的出现频数 | O(M×C): 其中C为字符在t中的出现频数 | 36ms (99.63%) |
LeetCode的Python执行用时随缘,只要时间复杂度没有明显差异,执行用时一般都在同一个量级,仅作参考意义。
解法一(动态规划:用双端队列存储状态):
使用双端队列存储状态适合于重复出现的状态没有意义的情形,并搭配集合来筛选状态;对于当前这种题目不适用。
class Solution:
def numDistinct(self, s: str, t: str) -> int:
N1 = len(s)
N2 = len(t)
D = N1 - N2
# 处理t比s场的特殊情况
if D < 0:
return 0
ans = 0
# 动态规划:使用双端队列存储当前状态
queue = collections.deque([(0, 0)])
while queue:
i1, i2 = queue.popleft()
if i2 == N2:
ans += 1
continue
if i1 < N1 and s[i1] == t[i2]:
queue.append((i1 + 1, i2 + 1))
if i1 < N1 and i1 - i2 < D:
queue.append((i1 + 1, i2))
return ans
解法二(动态规划:使用状态表格存储状态):
class Solution:
def numDistinct(self, s: str, t: str) -> int:
N1 = len(s)
N2 = len(t)
# 定义动态规划状态矩阵
matrix = [[0] * (N1 + 1) for _ in range(N2 + 1)]
matrix[0][0] = 1
# 计算首行的状态
for j in range(N1):
matrix[0][j + 1] = matrix[0][j]
# 计算状态转移数量
for i in range(1, N2 + 1):
for j in range(1, N1 + 1):
if t[i - 1] == s[j - 1]:
matrix[i][j] += matrix[i - 1][j - 1]
matrix[i][j] += matrix[i][j - 1]
return matrix[-1][-1]
解法三(动态规划:使用单个数组存储当前行状态):
class Solution:
def numDistinct(self, s: str, t: str) -> int:
N1 = len(s)
N2 = len(t)
# 处理字符串s比字符串t短的情况
if N1 < N2:
return 0
# 生成字符串中各个字符的坐标位置字典
count = collections.defaultdict(list)
for i, c in enumerate(t):
count[c].append(i)
stats = [1] + [0] * N2 # 当前行状态
for ch in s: # 遍历字符串s
for j in count[ch][::-1]: # 如果当前字符存在于j中,则遍历当前字符在j中的所有坐标
stats[j + 1] += stats[j] # 则累加当前位置的状态数
return stats[-1]