这道题目在大多数公司的笔试题目中都能找到踪迹,以前也遇到过很多这样的情况,其中蕴含的思想在字符串匹配,以及字符串其他操作上使用的非常丰富,而且,最重要的是,这是一类深度优先遍历转换为动归的典型题目。
题目的大致意思是,给定两个字符串,可以通过三种操作变化使两个字符串变为一样,分别是,修改,插入,删除。而总修改次数被称为两个字符串的距离,求出两个字符串变为相同字符串的最小距离是多少。
深度优先遍历肯定可以做,无非深度优先的时候别把代码写错了就行,这块不多说,主要来看动态规划。
动态规划解题思路:
其实对比两个字符串的时候,对应位置字符只有两种情况,一种是相同,一种是不同,假设相同,那其实不用发生任何变化,如果不同,才进行操作,而每个字符都对应于一种操作,又因为三个操作都是等价的,所以,可以使用动态规划,如果三个操作的代价不等价,则无法使用一个状态记录表来做,当然这是后话,就这道题而言,不用考虑这个。
根据上面一段的分析,我们可以得到状态转移方程
if (word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
if (word1[i-1] != word2[j-1]) dp[i][j] = min(dp[i-1][j], min(dp[i-1][j-1], dp[i][j-1]));
而dp[i][j]就表示word1的前i个字符组成的字串和word2的前j个字符组成的字串最小距离是多少。有了状态转移方程,则动态规划的代码就好写了,其实动归主要的目的就是理清思路,找到状态转移方程。
AC代码如下:
class Solution {
public:
int minDistance(string word1, string word2) {
int wsize1 = word1.size(), wsize2 = word2.size();
vector<vector<int>> dp(wsize1+1, vector<int>(wsize2+1, 0));
for (int j=1; j<dp[0].size(); ++j) {
dp[0][j] = j;
}
for (int i=1; i<dp.size(); ++i) {
dp[i][0] = i;
}
for (int i=1; i<dp.size(); ++i) {
for (int j=1; j<dp[0].size(); ++j) {
if (word1[i-1] == word2[j-1]) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = min(dp[i-1][j], min(dp[i][j-1], dp[i-1][j-1]))+1;
}
}
}
return dp[wsize1][wsize2];
}
};