题目
思路
- 思路一:暴力递归解决,由于对于每个字符不相等情况下我们有三种选择,1、删除该字符,2、替换该字符、3插入新字符,因此我们直接暴力尝试这三种可能性选择其中最小的
- 思路二:备忘录,由于暴力递归会超时,因此我们用容器将已经尝试过的结果记录下来,再进行选择。
思路三:动态规划,就是将递归变为循环,将递归的结果变成用dp数组记录下来,而dp数组的转移条件就是暴力中所提到的三个条件,关键在于如何定义dp数组,定义dp[i][j]表示word1的前i个字符到word2的前j个字符最短步骤 | 0 | 1 | 2 | | —- | —- | —- | | 1 | a | b | | 2 | c | d | | 3 | | |
思路四:优化dp数组的动态规划,在动态规划中,我们需要用到二维dp数组,但是从遍历来看,每次只用到了dp[i-1]p[j-1]和dp[i][j-1]和dp[i-1][j],因此我们需要记录一行结果和以及更新后结果,更新后的数据覆盖之前的结果,但是还要用到因此需要用prev记录覆盖之前的结果,比如计算a需要用到0、1、1,假设得到结果为1,然后放到数组对应的位置,继续计算b,需要用到1、a、2,但是由于a已经覆盖了1,所以需要额外变量记录1的结果
- prev = 1,计算b的值,下列表格显示的是第二行计算完a的dp数组结果 | 1 | 1 | 2 | | —- | —- | —- |
代码
//1、暴力递归超时public int minDistance(String word1, String word2) {return recur(word1.toCharArray(), 0, word2.toCharArray(), 0);}public int recur(char[] word1, int i, char[] word2, int j) {if (i >= word1.length || j >= word2.length) return word1.length + word2.length - i - j;if (word1[i] == word2[j]) return recur(word1, i + 1, word2, j + 1);return 1 + Math.min(//删除、替换、插入Math.min(recur(word1, i + 1, word2, j), recur(word1, i + 1, word2, j + 1)),recur(word1, i, word2, j + 1));}//2.备忘录HashMap<String, Integer> map = new HashMap<>();public int minDistance(String word1, String word2) {return recur(word1.toCharArray(), 0, word2.toCharArray(), 0);}public int recur(char[] word1, int i, char[] word2, int j) {String key = i + "-" + j;if (map.containsKey(key)) return map.get(key);if (i >= word1.length || j >= word2.length) return word1.length + word2.length - i - j;int res = 0;if (word1[i] == word2[j]) res = recur(word1, i + 1, word2, j + 1);else res = 1 + Math.min(Math.min(recur(word1, i + 1, word2, j), recur(word1, i + 1, word2, j + 1)),recur(word1, i, word2, j + 1));map.put(key, res);return res;}//3. 动态规划public int minDistance(String word1, String word2) {int len1 = word1.length();int len2 = word2.length();//dp[i][j]表示word1的i到word2的j的单词转换所需最小步骤int[][] dp = new int[len1 + 1][len2 + 1];for (int i = 0; i <= len1; i++) {dp[i][0] = i;}for (int j = 0; j <= len2; j++) {dp[0][j] = j;}for (int i = 1; i <= len1; i++) {for (int j = 1; j <= len2; j++) {if (word1.charAt(i - 1) == word2.charAt(j - 1)) {dp[i][j] = dp[i - 1][j - 1];} else {//插入、删除,替换dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);}}}return dp[len1][len2];}//4. 优化dp数组的动态规划public int minDistance(String word1, String word2) {int len1 = word1.length();int len2 = word2.length();//dp[j]表示到word2的j的单词转换所需最小步骤int[] dp = new int[len2 + 1];for (int j = 0; j <= len2; j++) {dp[j] = j;}for (int i = 1; i <= len1; i++) {int prev = i - 1;dp[0] = i;for (int j = 1; j <= len2; j++) {int t = dp[j];if (word1.charAt(i - 1) == word2.charAt(j - 1)) {dp[j] = prev;} else {//插入、删除,替换dp[j] = 1 + Math.min(Math.min(dp[j], dp[j - 1]), prev);}prev = t;}}return dp[len2];}
