72. 编辑距离
题目:
思路:
【1】动态规划对于这种肯定是需要多增加字符串为空的时候的处理的。
代码展示:
//时间6 ms 击败 11.34% //内存42.6 MB 击败 17.6% //时间复杂度 :O(mn),其中 m 为 word1 的长度,n 为 word2 的长度。 //空间复杂度 :O(mn),我们需要大小为 O(mn) 的 dp 数组来记录状态值。 class Solution { public int minDistance(String word1, String word2) { int n1 = word1.length(); int n2 = word2.length(); // 设置动态规划结果集 int[][] dp = new int[n1 + 1][n2 + 1]; // 第一行,假设word1 = "";是 word1 为空变成 word2 最少步数,就是插入操作 for (int j = 1; j <= n2; j++) dp[0][j] = dp[0][j - 1] + 1; // 第一列,,假设word2 = "";是 word1 为空变成 word2 需要的最少步数,就是删除操作 for (int i = 1; i <= n1; i++) dp[i][0] = dp[i - 1][0] + 1; // 分析当两者都不为空 for (int i = 1; i <= n1; i++) { for (int j = 1; j <= n2; j++) { // 如果两者当前的字符是匹配的,那么其实就不需要增加操作步骤,故直接记录到上一步的操作数即可 if (word1.charAt(i - 1) == word2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1]; }else { // 如果两者不等,dp[i-1][j-1] 表示替换操作,dp[i-1][j] 表示删除操作,dp[i][j-1] 表示插入操作。 // 因为dp[i-1][j-1]相当于在之前的操作上加上把当前字符变更的操作 // 而dp[i-1][j] 相当于删除了word1中的这个字符,就会回到word1上个字符到当前位置的步骤 // 而dp[i][j-1] 相当于删除了word2中的这个字符,就会回到word2上个字符到当前位置的步骤 // 其实这里相当于有两个删除,为什么?因为不知道是word1更长还是word2更长 // 因为由长变短的操作步数和由短变长的是一样的,理论上只要确保word1更长的话可以减少一次比较 dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1; } } } return dp[n1][n2]; } } //相反下面这种会更直观一些 //时间2 ms击败 100% //内存42.5 MB击败32.88% //这种递归次数相反会比上面的更少,毕竟三次递归 //最长不过(m+n)*3,比上面的m*n会好很多 class Solution { public int minDistance(String word1, String word2) { if(word1 == null || word2 == null){ throw new IllegalArgumentException(); } //word1变成word2 指针指向最后一个位置 依次比较 先定义好递归函数 //二维数组的索引有意义 int[][] mon = new int[word1.length()][word2.length()]; for(int[] row : mon){ Arrays.fill(row,-1); } return doMinDistance(word1,word1.length()-1,word2,word2.length()-1,mon); } // word1 从0到l word2 从0到r 最小编辑距离 private int doMinDistance(String word1,int l,String word2,int r,int[][] mon){ //l已经遍历完了 word2剩余r+1个字符 需要插入r+1; if(l==-1) return r+1; if(r==-1) return l+1; if(mon[l][r]!=-1){ return mon[l][r]; } if(word1.charAt(l) == word2.charAt(r)){ mon[l][r] = doMinDistance(word1,l-1,word2,r-1,mon); }else { mon[l][r] = min( //插入 doMinDistance(word1,l,word2,r-1,mon)+1, //替换 doMinDistance(word1,l-1,word2,r-1,mon)+1, //删除 doMinDistance(word1,l-1,word2,r,mon)+1 ); } return mon[l][r]; } private int min(int a , int b ,int c){ return Math.min(a,Math.min(b,c)); } }