题目大意:给定两个字符串,求解将 word1 转化成 word2 的最小操作。操作有三个,替换,增加和删除。
题目分析:突然给定一个这样的题目,求解有效可能集合中的最优解。第一想法当然就想到了动态规划,可是怎么找状态转移方程呢?又应该选择哪个状态呢?一般能想到两个,一个是dp[i][j], 表示长度为 i 的Word1 转化为长度为 j 的word2所需要的最小操作数;另一个就是用一维数组了,dp[i] 表示长度为 i 的word1转化成Word2所需的最小操作数(i也可用来表示Word2长度)。这里只是两种初步可能的表达,是否合适还要继续分析,这里我选择了二维数组的表示方法,因为一维的想不出(可能别人有这个解法)。
既然确定了求解的状态,那是否满足状态转移呢?当然这里是有的,有 dp[i-1][j-1] 到 dp[i][j] 的状态转移(dp[i][j])。现在来分析 dp[i][j] 的可能构成:Word1 到 Word2有三种操作
1)如果word1[i]==word2[j], 那么 dp[i][j] = dp[i-1][j-1]. 当然可能有人会说还有,dp[i-1][j] + 1(删除word[i], 加上dp[i-1][j]), 甚至有dp[i][j-1]+1 (表示 新增一个 word1[i+1]=word2[j], 从而加上dp[i][j-1])。但其实是不可能的,其实dp[i-1][j-1]<=dp[i][j-1]+1 , dp[i-1][j]+1,这个自己演算一下就知道了。
2) 如果word1[i]!=word2[j],那么现在这上面分析的三种情况可能发生了:
dp[i-1][j-1] +1: 同上分析,表示将word1[i] 替换成 word2[j],加上dp[i-1][j-1]
dp[i-1][j] +1 : 表示删除word[i], 加上dp[i-1][j]
dp[i][j-1] +1 : 表示 插入一个 word1[i+1]=word2[j], 从而加上dp[i][j-1]
分析完毕,编码阶段。直接给出代码:
class Solution {
public:
int minDistance(string word1, string word2) {
int len1 = word1.size();
int len2 = word2.size();
if(len1==0 || len2==0) return len1 + len2;
int dp[len1+1][len2+1] = {0}; // 为了避免边界讨论,数组开大了一点
for(int i=0;i<=len1;i++){ // 表示word1 为空,即插入全部word2
dp[i][0] = i;
}
for(int i=0;i<=len2;i++){ // 表示word2 为空,即删除全部word1
dp[0][i] = i;
}
for(int i=0;i<len1;i++){ // 这里是 dp[i+1][j+1] 为求解单位, 也可从1->len这样遍历
for(int j=0;j<len2;j++){
if(word1[i]==word2[j]) dp[i+1][j+1] = dp[i][j];
else {
dp[i+1][j+1] = min(dp[i][j]+1, min(dp[i][j+1]+1, dp[i+1][j]+1));
}
}
}
return dp[len1][len2];
}
};