字串A->字串B例題 :最短編輯距離、最優包含 (線性DP)
阿新 • • 發佈:2021-12-31
AcWing 902. 最短編輯距離
給定兩個字串A和B,現在要將A經過若干操作變為B,可進行的操作有:
- 刪除–將字串A中的某個字元刪除。
- 插入–在字串A的某個位置插入某個字元。
- 替換–將字串A中的某個字元替換為另一個字元。
現在請你求出,將A變為B至少需要進行多少次操作。
輸入格式
第一行包含整數n,表示字串A的長度。
第二行包含一個長度為n的字串A。
第三行包含整數m,表示字串B的長度。
第四行包含一個長度為m的字串B。
字串中均只包含大寫字母。
輸出格式
輸出一個整數,表示最少操作次數。
資料範圍
1≤n,m≤1000
輸入樣例:
10
AGTCTGACGC
11
AGTAAGTAGGC
輸出樣例:
4
題解
狀態表示 dp[i][j]
- 集合 : 所有把a[1~i]變成 b[1~j]的集合的操作集合
- 屬性 : 所有操作中操作次數最少的方案的運算元
狀態計算
狀態劃分 以對a中的第i個字母操作不同劃分
-
在該字母之後新增
新增一個字母之後變得相同,說明沒有新增前a的前i個已經和b的前j-1個已經相同
即 : dp[i][j] = dp[i][j-1] + 1 -
刪除該字母
刪除該字母之後變得相同,說明沒有刪除前a中前i-1已經和b的前j個已經相同
即 : dp[i][j] = dp[i-1][j] + 1 -
替換該字母
- 替換說明對應結尾字母不同,則看倒數第二個
即: dp[i][j] = dp[i-1][j-1] + 1
啥也不做 - 對應結尾字母相同,直接比較倒數第二個
即: dp[i][j] = dp[i-1][j-1]
- 替換說明對應結尾字母不同,則看倒數第二個
n = int(input()) s1 = input() s1 = " " + s1 m = int(input()) s2 = input() s2 = " " + s2 dp = [[1e18] * (m + 1) for i in range(n + 1)] # 邊界情況 # 只能刪除 for i in range(1, n + 1): dp[i][0] = i # 只能新增 for j in range(1, m + 1): dp[0][j] = j dp[0][0] = 0 for i in range(1, n + 1): for j in range(1, m + 1): # 改 if s1[i] == s2[j]: dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]) else: dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1) # 刪 dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1) # 加 dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1) print(dp[-1][-1])
2553. 最優包含
我們稱一個字串 S 包含字串 T 是指 T 是 S 的一個子序列,即可以從字串 S 中抽出若干個字元,它們按原來的順序組合成一個新的字串與 T 完全一樣。
給定兩個字串 S 和 T,請問最少修改 S 中的多少個字元,能使 S 包含 T?
輸入格式
輸入兩行,每行一個字串。
第一行的字串為 S,第二行的字串為 T。
兩個字串均非空而且只包含大寫英文字母。
輸出格式
輸出一個整數,表示答案。
資料範圍
1≤|T|≤|S|≤1000
輸入樣例:
ABCDEABCD
XAABZ
輸出樣例:
3
題解
狀態表示 dp[i][j]
- 集合 : 所有把a[1~i]變成 b[1~j]的集合的操作集合
- 屬性 : 所有操作中操作次數最少的方案的運算元
狀態計算
狀態劃分 以對a中的第i個字母操作不同劃分
- 不變
與上題不同,這是一個子序列。
dp[i][j] = dp[i - 1][j] - 替換該字母
- 替換說明對應結尾字母不同,則看倒數第二個
即: dp[i][j] = dp[i-1][j-1] + 1
啥也不做 - 對應結尾字母相同,直接比較倒數第二個
即: dp[i][j] = dp[i-1][j-1]
- 替換說明對應結尾字母不同,則看倒數第二個
s1 = input()
s2 = input()
n = len(s1)
m = len(s2)
s1 = " " + s1
s2 = " " + s2
dp = [[1e18] * (m + 1) for i in range(n + 1)]
for i in range(0, n + 1):
dp[i][0] = 0
for i in range(1, n + 1):
for j in range(1, m + 1):
dp[i][j] = min(dp[i][j], dp[i - 1][j])
if s1[i] == s2[j]:
dp[i][j] = min(dp[i][j], dp[i-1][j-1])
else:
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1)
print(dp[-1][-1])