編輯距離算是一個比較經典的問題,可以用於常見的拼寫糾錯。
1.Leetcode 72編輯距離
- 題目描述
給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少操作數 。
你可以對一個單詞進行如下三種操作:
插入一個字符
刪除一個字符
替換一個字符
示例 1:
輸入: word1 = "horse", word2 = "ros"
輸出: 3
解釋:
horse -> rorse (將 'h' 替換爲 'r')
rorse -> rose (刪除 'r')
rose -> ros (刪除 'e')
示例 2:
輸入: word1 = "intention", word2 = "execution"
輸出: 5
解釋:
intention -> inention (刪除 't')
inention -> enention (將 'i' 替換爲 'e')
enention -> exention (將 'n' 替換爲 'x')
exention -> exection (將 'n' 替換爲 'c')
exection -> execution (插入 'u')
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/edit-distance
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
- 思路分析
對於兩個字符串,我們從右到左進行比較:
當a[i]==b[i]那麼我們需要做任何操作,操作次數和a[i-1]與b[i-1]的操作次數相同。
如果不相等,那麼我們有三種選擇:第一種,刪除a的當前元素(操作次數1)+以a[i-1]結尾串和以b[i]結尾串的操作次數;第二種,在當前位置插入一個元素,使得其與b[i]相等(操作次數1)+以a[i]結尾串與以b[i-1]結尾串的操作次數;第三種情況,替換a[i]使其等於b[i](操作次數1)+以a[i-1]結尾串和以b[i-1]結尾串的操作次數。在這三種情況裏,選擇一個操作次數最少的。
當其中一個串空是,最短的操作次數就是另外一個串的長度。
- 代碼設計
- 遞歸版本
class Solution {
public:
//遞歸超時
int MinDistance(string word1,string word2,int w1,int w2)
{
if(w1==0)
return w2;
else if(w2==0)
return w1;
else if(word1[w1-1]==word2[w2-1])
return MinDistance(word1,word2,w1-1,w2-1);
return 1+min(MinDistance(word1,word2,w1,w2-1),min(MinDistance(word1,word2,w1-1,w2),MinDistance(word1,word2,w1-1,w2-1)));
}
int minDistance(string word1, string word2) {
int w1=word1.size();
int w2=word2.size();
return MinDistance(word1,word2,w1,w2);
}
};
- 動態規劃版本(時間複雜度N^2,空間複雜度N^2)
class Solution {
public:
//N*N的空間 N*N的時間複雜度
int minDistance(string word1, string word2) {
int w1=word1.size();
int w2=word2.size();
vector<vector<int>>dp(w1+1,vector<int>(w2+1,0));
//dp[i][j]:表示長度爲i的字符串1與長度爲j的字符串2需要的操作次數
for(int i=0;i<=w1;++i)
{
for(int j=0;j<=w2;++j)
{
if(j==0)//如果str2爲空串 把str1全部刪除
dp[i][j]=i;
else if(i==0)//同理s1爲空串
dp[i][j]=j;
else if(word1[i-1]==word2[j-1])
dp[i][j]=dp[i-1][j-1];
else
{
dp[i][j]=1+min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1]));
}
}
}
return dp[w1][w2];
}
};
- 動態規劃改進版本(時間複雜度N^2空間複雜度N)
class Solution {
public:
//N*N的空間 N*N的時間複雜度
int minDistance(string word1, string word2) {
int w1=word1.size();
int w2=word2.size();
vector<vector<int>>dp(2,vector<int>(w1+1,0));
//其實可以發現我們每次更新的時候 狀態只和其前一行有關係
//我們以str1作爲基準 來比如
for(int i=0;i<=w1;++i)
{
dp[0][i]=i;//假設str2爲空
}
//i%2的作用就是取交替下標0,1
for(int i=1;i<=w2;++i)
{
for(int j=0;j<=w1;++j)
{
if(j==0)//如果str1爲空 i%2=0去當前位置p[0]
dp[i%2][j]=i;
else if(word1[j-1]==word2[i-1])
dp[i%2][j]=dp[(i-1)%2][j-1];//和i-1,j-1一樣
else
{
dp[i%2][j]=1+min(dp[(i-1)%2][j],min(dp[i%2][j-1],dp[(i-1)%2][j-1]));
}
}
}
return dp[w2%2][w1];
}
};