if s1[i] == s2[j]: 不做操作,直接跳过skip i,j同时向前移动 else: 操作 3 选 1: 插入-insert 删除-delete 替换-replace 复制代码
def minDistance(s1, s2) -> int: # 返回s1[0,..., i]和s2[0, ..., j]的最小编辑距离 def dp(i, j): # base case if i == -1: return j + 1 if j == -1: return i + 1 if s1[i] == s2[j]: # 不需要进行任务操作 # s1[0,..., i]和s2[0, ..., j]的最小编辑距离等于s1[0,..., i - 1]和s2[0, ..., j - 1]的最小编辑距离 # 即dp(i, j)等于dp(i - 1, j - 1) return dp(i - 1, j - 1) else: return min( # 插入 # 在s1[i]中插入1个和s2[j]一样的字符就可以匹配 # 将s2的字符前移1位,继续比对 # 插入操作,操作数加1 dp(i, j - 1) + 1 # 删除 # 将s1[i]中删除这1个字符就可以匹配 # 将s2的字符前移1位,继续比对 # 删除操作,操作数加1 dp(i - 1, j) + 1 # 替换 # 将s1[i]替换成s2[j]就可以继续匹配 # 同时i,j前移1位,继续比对 # 替换操作,操作数加1 dp(i - 1, j - 1) + 1 ) return dp(len(s1) - 1, len(s2) - 1) 复制代码
- 如何判断是否存在重叠子问题?
- 抽象出解法的算法框架
- 判断子问题到原问题的不同路径
- 一旦存在重复的路径,就说明存在巨量的重复路径,也就是存在重叠子问题
def minDistance(s1, s2) -> int: # 备忘录 memo = dict() def dp(i, j): if (i, j) in memo: return memo[(i, j)] ... if s[i] == s[j]: memo[(i, j)] = ... else: memo[(i, j)] = ... return memo[(i, j)] return dp(len(s1) - 1, len(s2) - 1) 复制代码
int minDistance(String s1, String s2) { int m = s1.length(), n = s2.length(); int[][] dp = new int[m][n]; // base case for (int i = 1; i <=m; i++) { dp[i][0] = i; } for (int j = 1; j <= n; j++) { dp[0][j] = j; } // 自底向上计算DP Table for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (s1.isCharAt(i) == s2.isCharAt(j)) { dp[i][j] = dp[i - 1][j - 1]; } else { dp = min( // 删除 dp[i - 1][j] + 1; // 替换 dp[i - 1][j - 1] + 1; // 插入 dp[i][j - 1] + 1; ); } } } // 存储s1和s2的最小编辑距离 return dp[m][n]; } int min(int a, int b, int c) { return Math.min(a, Math.min(b, c)); } 复制代码
Node[][] dp; class Node { // 之前dp数组的数值 int val; // 属性操作 int choice; } 复制代码
- 最小编辑距离Java实现
- 最小编辑距离C++实现:
class DynamicProgramming { public: int minDistance(String s1, String s2) { int m = s1.size(), n = s2.size(); vector<vector<int>> dp(m + 1, vector<int>(n + 1)); // basecase // 当字符串s2为空时,字符串s1需要删除所有字符才能和s2相同 for (int i = 1; i <= m; i++) { dp[i][0] = i; } // 当字符串s1为空时,字符串s2需要删除所有字符才能和s1相同 for (int j = 1; j <= n; j++) { dp[0][j] = j; } // 自底向上求解 for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (s1[i - 1] == s2[j - 1]) { // 两个字符串当前的字符相等 dp[i][j] = dp[i - 1][j - 1]; } else { // 两个字符串当前的字符不相同 dp[i][j] = min({ // 删除s1[i]这个字符 dp[i - 1][j] + 1, // 在s1[i]字符后面添加一个与s2[j]相同的字符 dp[i][j - 1] + 1, // 将s1[i]的字符替换为s2[j]的字符 dp[i - 1][j - 1] + 1 }); } } } // 储存整个s1和s2的最小编辑距离 return dp[m][n]; } };