该类问题基本可以用动态规划进行求解,定义dp[i][j]/dp[i]表示以下表为 i -1 和j - 1 时的个数为dp[i][j]/dp[i].这种定义与之前的最长公共序列相关问题类似,i-1也表示的是以下标i-1结尾时的最长/最大公共序列为dp[i]。
判断子序列
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
m = len(s)
n = len(t)
if m > n: return False
dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if s[i - 1] == t[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = dp[i][j - 1]
return dp[-1][-1] == m
该题也可以使用双指针做法,当前两个字符相等时,则两个指针都进行加一,否则只对t的指针进行加一操作,代码如下:
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
m, n = len(s), len(t)
l, r = 0, 0
while l < m and r < n:
if s[l] == t[r]:
l += 1
r += 1
return l == m
不同的子序列
class Solution:
def numDistinct(self, s: str, t: str) -> int:
m, n = len(s), len(t)
# dp[i][j]:S前i个,T前j个字符串组成的最多个数
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = 1
for i in range(1, m + 1):
for j in range(1, n + 1):
if s[i - 1] == t[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
else:
dp[i][j] = dp[i -1][j]
return dp[-1][-1]
两个字符串的删除操作
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[float('inf')] * (n + 1) for _ in range(m + 1)]
for i in range(n + 1):
dp[0][i] = i
for i in range(m + 1):
dp[i][0] = i
for i in range(1, m + 1):
for j in range(1, n + 1):
if word1[i - 1] == word2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j - 1] + 2, dp[i][j - 1] + 1, dp[i - 1][j] + 1)
return dp[-1][-1]
编辑距离
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(n + 1):
dp[0][i] = i
for i in range(m + 1):
dp[i][0] = i
for i in range(1, m + 1):
for j in range(1, n + 1):
if word1[i - 1] == word2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j -1] + 1)
return dp[-1][-1]
另外一种解法:
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
import functools
@functools.lru_cache(None)
def helper(i, j):
if i == len(word1) or j == len(word2):
return len(word1) - i + len(word2) - j
if word1[i] == word2[j]:
return helper(i + 1, j + 1)
else:
inserted = helper(i, j + 1)
deleted = helper(i + 1, j)
replaced = helper(i + 1, j + 1)
return min(inserted, deleted, replaced) + 1
return helper(0, 0)