由于我们的目的求将 word1 转换成 word2 所使用的最少操作数 。那我们就定义 dp[i] [j]的含义为:当字符串 word1 的长度为 i,字符串 word2 的长度为 j 时,将 word1 转化为 word2 所使用的最少操作次数为 dp[i] [j]。
由于我们是要让操作的次数最小,所以我们要寻找最佳操作。那么有如下关系式:
一、如果我们 word1[i] 与 word2 [j] 相等,这个时候不需要进行任何操作,显然有 dp[i] [j] = dp[i-1] [j-1]。
二、如果我们 word1[i] 与 word2 [j] 不相等,这个时候我们就必须进行调整,而调整的操作有 3 种,我们要选择一种。三种操作对应的关系试如下(注意字符串与字符的区别):
(1)、如果把字符 word1[i] 替换成与 word2[j] 相等,则有 dp[i] [j] = dp[i-1] [j-1] + 1;
(2)、如果在字符串 word1末尾插入一个与 word2[j] 相等的字符,则有 dp[i] [j] = dp[i] [j-1] + 1;
(3)、如果把字符 word1[i] 删除,则有 dp[i] [j] = dp[i-1] [j] + 1;
那么我们应该选择一种操作,使得 dp[i] [j] 的值最小,显然有
dp[i] [j] = min(dp[i-1] [j-1],dp[i] [j-1],dp[[i-1] [j]]) + 1;
当 dp[i] [j] 中,如果 i 或者 j 有一个为 0,这个时候把 i - 1 或者 j - 1,就变成负数了,数组就会出问题了,所以我们的初始值是计算出所有的 dp[0] [0….n] 和所有的 dp[0….m] [0]。这个还是非常容易计算的,因为当有一个字符串的长度为 0 时,转化为另外一个字符串,那就只能一直进行插入或者删除操作了。
int dp[1000][1000] = { 0 }; //将 word1 转化为 word2 所使用的最少操作次数
int main()
{
string word1, word2;
cin >> word1 >> word2;
int n1 = word1.length();
int n2 = word2.length();
for (int i = 1; i <= n1; i++)//dp[0...n1][0]的初始值
dp[i][0] = dp[i - 1][0] + 1;
for (int i = 1; i <= n2; i++)//dp[0][0...n2]的初始值
dp[0][i] = dp[0][i - 1] + 1;
for (int i = 1; i <= n1; i++)//通过公式推出dp[n1][n2]
{
for (int j = 1; j <= n2; j++)
{
if (word1[i - 1] == word2[j - 1])//第i个字符对应的下标为i-1
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = min(min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
}
}
cout << dp[n1][n2] << endl;
return 0;
}