题目:leetcode
Edit Distance
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)
You have the following 3 operations permitted on a word:
a) Insert a character
b) Delete a character
c) Replace a character
方法一:记忆化递归
每次递归时,都进行三种操作。注意:1、插入操作的运行条件需要重点留意。2、自定义的node类型的哈希函数应该设置得好一点,这里使用c++默认哈希函数。
class node
{
public:
string w1;
string w2;
node(string a,string b):w1(a),w2(b){}
bool operator==(const node &rch)const
{
if( (rch.w1==w1 && rch.w2==w2) || (rch.w2==w1 && rch.w1==w2) )
return true;
else
return false;
}
};
struct hash_node
{
size_t operator()(const node &r)const
{
std::hash<std::string> h;
size_t n1 = h(r.w1);
size_t n2 = h(r.w2);
return n1^n2;
//return hash<char>()(r.w1[0]) ^ hash<char>()(r.w2[0]);
}
};
class Solution {
public:
int minDistance(string word1, string word2) {
if(word1.empty())
return word2.size();
if(word2.empty())
return word1.size();
//删除相同的前缀
if(word1[0]==word2[0])
{
int i=0;
for(;i<word1.size() && i<word2.size() ;i++)
{
if(word1[i]!=word2[i])
break;
}
if(i==word1.size() || i==word2.size())
{
int size1=word1.size(),size2=word2.size();
return abs(size1-size2);
}
word1.erase(word1.begin(),word1.begin()+i);
word2.erase(word2.begin(),word2.begin()+i);
}
unordered_map<node,int,hash_node> table;
size_t up=word1.size()+word2.size();//该参数是Insert a character的上限
return minDistance_core(word1,word2,table,up);
}
int minDistance_core(string w1, string w2,unordered_map<node,int,hash_node> &table,size_t up)
{
if(w1.empty())
return w2.size();
if(w2.empty())
return w1.size();
node a(w1,w2);
if(table.count(a)>0)
return table[a];
//删除相同的前缀
if(w1[0]==w2[0])
{
int i=0;
for(;i<w1.size() && i<w2.size() ;i++)
{
if(w1[i]!=w2[i])
break;
}
if(i==w1.size() || i==w2.size())
{
int size1=w1.size(),size2=w2.size();
int res= abs(size1-size2);
table[a]=res;
return res;
}
w1.erase(w1.begin(),w1.begin()+i);
w2.erase(w2.begin(),w2.begin()+i);
}
//Replace a character
string s1=w1.substr(1,w1.size()-1);
string s2=w2.substr(1,w2.size()-1);
int res1=1+minDistance_core(s1,s2,table,up);
//Insert a character
int res2=0x7fffffff;
bool flag=false;
for(auto &i:w2)
{
if(i==w1[0])
{
flag=true;
break;
}
}
//只有当w1的长度小于上限,且w1[0]在w2中有出现,才进行插入操作
if(w1.size()<up && flag)
res2=1+minDistance_core(w1,s2,table,up);
//Delete a character
int res3=1+minDistance_core(s1,w2,table,up);
int res=min(res1,res2);
res=min(res,res3);
table[a]=res;
return res;
}
};
方法二:动态规划
用f[i][j]表示A[0,i]和B[0,j]之间的最小编辑距离。先初始化i==0和j==0的情况,然后f[i][j]=1+min(f[i-1][j],f[i][j-1],f[i-1][j-1]).
int minDistance(string word1, string word2) {
if(word1.empty())
return word2.size();
if(word2.empty())
return word1.size();
//删除相同的前缀
if(word1[0]==word2[0])
{
int i=1;
for(;i<word1.size() && i<word2.size() ;i++)
{
if(word1[i]!=word2[i])
break;
}
if(i==word1.size() || i==word2.size())
{
int size1=word1.size(),size2=word2.size();
return abs(size1-size2);
}
word1.erase(word1.begin(),word1.begin()+i);
word2.erase(word2.begin(),word2.begin()+i);
}
vector<vector<int>> f(word1.size(),vector<int>(word2.size(),0));
bool same=false;
for(int i=0;i<word1.size();i++)
{
if(same)
{
f[i][0]=f[i-1][0]+1;
continue;
}
if(word1[i]==word2[0])
{
same=true;
f[i][0]=i;
}
else
{
f[i][0]=i+1;
}
}
same=false;
for(int j=0;j<word2.size();j++)
{
if(same)
{
f[0][j]=f[0][j-1]+1;
continue;
}
if(word2[j]==word1[0])
{
same=true;
f[0][j]=j;
}
else
{
f[0][j]=j+1;
}
}
for(int i=1;i<word1.size();i++)
{
for(int j=1;j<word2.size();j++)
{
if(word1[i]==word2[j])
f[i][j]=f[i-1][j-1];
else
{
int tmp=min(f[i-1][j],f[i][j-1]);
tmp=min(tmp,f[i-1][j-1]);
f[i][j]=tmp+1;
}
}
}
return f.back().back();
}