編輯最短距離

2021-08-06 00:09:55 字數 2789 閱讀 9929

給定兩個字串s和t,對於t我們允許三種操作:

(1) 在任意位置新增任意字元

(2) 刪除存在的任意字元

(3) 修改任意字元 

問最少操作多少次可以把字串t變成s? 

例如: s=  「abcf」   t = 「dbfg」

那麼我們可以

(1) 把d改為a

(2) 刪掉g

(3) 加入c

所以答案是3。

(1) 把t中字元全刪了,再新增s的全部字元,操作次數m + n。

(2) 把t中字元刪或加成m個,再修改 操作次數最多 |n – m| + m。

這個問題之所以難,是難在有「新增」「刪除」這樣的操作,很麻煩。我們試試換個角度理解問題,把它看成字串對齊的問題,事實上從生物資訊學對比基因的角度,我們可以這樣理解問題。

給定字串s和t,我們可以用一種特殊字元促成兩個字串的對齊。我們加的特殊字元是「-」, 我們允許在s和t中任意新增這種特殊字元使得它長度相同,然後讓這兩個串「對齊」,最終兩個串相同位置出現了不同字元,就扣1分,我們要使得這兩個串對齊扣分盡量少。

對於例子 我們實際上採取了這樣的對齊方式:

12345

abcf-

db-fg

注意:如果要對齊,兩個「-」相對是沒有意義的,所以我們要求不出現這種情況。

那麼看一下:

(1) s,t對應位置都是普通字元,相同,則不扣分。 例如位置2,4

(2) s,t對應位置都是普通字元,不同,則扣1分。 例如位置1

(3) s在該位置是特殊字元,t在該位置是普通字元,則扣1分,例如位置5

(4) s在該位置是普通字元,t在該位置是特殊字元,則扣1分,例如位置

我們來看看扣分專案對應什麼?

(1) 不扣分,直接對應

(2) 對應把t中對應位置的字元修改

(3) 對應在t中刪除該字元

(4) 對應在t中新增該字元

好了,目標明確,感覺像不像 lcs?我們嘗試一下:

設f(i,j)表示s的前i位和t的前j位對齊後的最少扣分。

那我們來看看最後一位,對齊的情況

(1) 必須s[i] == t[j], 這時前i – 1和j – 1位都已經對齊了,這部分肯定要最少扣分。這種情況下最少的扣分是f(i-1,j-1)

(2) 和(1)類似,s[i]≠t[j],這種情況下最少的扣分是f(i -1, j – 1) + 1

(3) s的前i位和t的前(j – 1)位已經對齊了,這部分扣分也要最少。這種情況下最少的扣分是f(i,j-1) + 1

(4) s的前(i-1)位已經和t的前j位對齊了,這部分扣分要最少。這種情況下最少的扣分是f(i,j-1) + 1

具體f(i,j)取什麼值,顯然是要看哪種情況的扣分最少。

雖然,我們找到了這樣的上界,bfs從實際角度並不可行,因為搜尋空間是指數的,這取決於s中的字元種類——具體的數量級不好估計。

為了方便,我們定義函式same(i,j)表示如果s[i] == t[j]則為0,否則為1。

我們來表示一下遞推式:

f(i,j) = min(f(i – 1, j – 1) + same(i,j), f(i – 1,j ) + 1, f(i, j – 1) + 1)

初值是什麼?

f(0, j) = j

f(i, 0) = i

這時因為對於s的前0位,我們只能在之前加入「-」,或者說把t全部刪掉了。類似地,對於t地前0位,我們只能把s的字元都加進來,別無選擇。

注意上述兩個式子的重合點 f(0,0) = 0也符合我們的定義,並不矛盾。

時間複雜度? o(m * n),空間複雜度? o(m * n)。同樣我們發現到f(i,j)只與本行和上一行有關,可以省掉一維的空間複雜度,從而達到o(n),優化後的偽**:

for j = 0 to n do

f[j] = j

endfor

for i = 1 to m do

last = f[0]

f[0] = i

for j = 1 to n do 

temp = f[i,j]

f[i,j] = min(last + same(i,j), temp + 1, f[j – 1] + 1)

last = temp

endfor

endfor

注意: 我們對於i實際上更新j的順序是由小到達的,所以我們需要儲存「舊的」f[i-1,j – 1]。

輸入

第1行:字串a(a的長度 <= 1000)。

第2行:字串b(b的長度 <= 1000)。

輸出

輸出a和b的編輯距離

輸入示例

kitten

sitting

輸出示例

3

#include#include#includeusing namespace std;  

char a[1010];

char b[1010];

int same[1010][1010];

int dp[1010][1010];

int lena,lenb;

void init()

} }

int main()

} printf("%d\n",dp[lena][lenb]);

return 0;

}

1407 最短距離

兩個點 a b 均在做勻速直線運動。給出 t 0時刻 a b 的座標,以及 a b 的速度,計算t 0時兩個點的距離的最小值。輸入的第一行包含乙個整數 t 1 t 200 表示一共有 t 組測試資料。對於每組測試資料,第一行包含4個整數 x a y a v ax v ay 103 x a y a v...

素數最短距離問題

素數距離問題 時間限制 3000 ms 記憶體限制 65535 kb 難度 2 描述現在給出你一些數,要求你寫出乙個程式,輸出這些整數相鄰最近的素數,並輸出其相距長度。如果左右有等距離長度素數,則輸出左側的值及相應距離。如果輸入的整數本身就是素數,則輸出該素數本身,距離輸出0 輸入第一行給出測試資料...

線段間最短距離

計算平面上兩條線段之間的最短距離 兩線段用其端點s1 p1a,p1b s2 p2a,p2b 表示 s1,s2上距離最近的兩點之間的距離d s1,s2 定義為。分為三種情況討論。a.若兩線段有交點,距離d為0 b.計算兩線段端點到對方線段所在直線l1,l2的距離。d p1a,l2 d p1b,l2 d...