目录
题目:
示例:
分析:
代码:
题目:
示例:
分析:
题目给我们三种操作方式,插入一个字符,删除一个字符,替换一个字符。
问我们最少操作几次可以把字符串1变成字符串2。
那么同样是两个字符串的动态规划,我们可以参考一下前两题最长公共子序列的dp数组。
dp[ i ][ j ]表示为当字符串1的长度为 i ,字符串2的长度为 j 时,所需的最小操作次数。
那么确定了dp数组的含义之后,我们需要找到递推公式。
首先如果字符串1的第 i 个字符等于字符串2的第 j 个字符,那么它们的最小操作次数就应该等于dp[ i - 1 ][ j - 1],也就是不用操作。
那么重点是如果字符不一样呢。
题目给了我们三种操作方法,我们应该怎么在代码里体现出来呢。
假设两个字符不一样,我用的是删除操作,那么就等于是让字符串1的长度少了一节,也就是说操作次数应该是dp[ i - 1 ][ j ] + 1 。
如果用的是插入操作,那么就等于是字符串1的长度多了一节,但是我们没法在dp数组里体现出来,那我们换一个思路,我对字符串1进行插入操作,是不是就等于是我跳过了比较字符串2的第 j 个字符。那么最小操作次数就是dp[ i ][ j - 1 ] + 1 。
最后就是替换操作,替换操作可以看成是先删除再插入,所以可以写成是dp[ i - 1][ j + 1 ] + 1 。
至此我们就找到了递归公式:
最后就剩一个初始化,由于递推公式里需要对 i 和 j 进行 -1 的操作,所以 i 和 j 都至少需要1。
因此我们需要初始化 i=0 和 j = 0的情况。
这两种情况分别是字符串1的长度为0以及字符串2的长度为0的情况。
字符串1的长度为0时,最小操作次数就是字符串2的长度,因为只有对字符串1执行那么多次的插入操作才可以使得他们相同。字符串2的长度为0时也是一样的,只能对字符串1执行那么多次的删除操作。
最后返回dp数组的最后一个元素即可。
代码:
class Solution {
public:
int minDistance(string word1, string word2) {
int n=word1.size();int m=word2.size();
vector<vector<int>>dp(n+1,vector<int>(m+1));
for(int i=1;i<n+1;i++) dp[i][0]=i;
for(int i=1;i<m+1;i++) dp[0][i]=i;
for(int i=1;i<n+1;i++){
for(int j=1;j<m+1;j++){
if(word1[i-1]==word2[j-1]){ //字符相同则保持之前的最少操作数
dp[i][j]=dp[i-1][j-1];
}else{//字符不同则操作
//dp[i-1][j]+1为插入操作
//dp[i-1][j-1]+1为替换操作
//dp[i][j-1]+1为删除操作
//挑一个操作数最小的作为dp[i][j]
dp[i][j]=min({dp[i-1][j],dp[i-1][j-1],dp[i][j-1]})+1;
}
}
}
return dp[n][m];
}
};