LeetCode-72. Edit Distance (JAVA)字符串最小编辑距离DP&DFS

72. Edit Distance

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character
b) Delete a character
c) Replace a character

给定一个源串和目标串,能够对源串进行如下操作:
1.在给定位置上插入一个字符
2.替换任意字符
3.删除任意字符

This is a classic problem of Dynamic Programming. We define the state dp[i][j] to be the minimum number of operations to convert word1[0..i - 1] to word2[0..j - 1]. The state equations have two cases: the boundary case and the general case. Note that in the above notations, both i and j take values starting from 1.

For the boundary case, that is, to convert a string to an empty string, it is easy to see that the mininum number of operations to convert word1[0..i - 1] to "" requires at least i operations (deletions). In fact, the boundary case is simply:

  1. dp[i][0] = i;
  2. dp[0][j] = j.

Now let's move on to the general case, that is, convert a non-empty word1[0..i - 1] to another non-empty word2[0..j - 1]. Well, let's try to break this problem down into smaller problems (sub-problems). Suppose we have already known how to convert word1[0..i - 2] to word2[0..j - 2], which is dp[i - 1][j - 1]. Now let's consider word[i - 1] and word2[j - 1]. If they are euqal, then no more operation is needed and dp[i][j] = dp[i - 1][j - 1]. Well, what if they are not equal?

If they are not equal, we need to consider three cases:

  1. Replace word1[i - 1] by word2[j - 1] (dp[i][j] = dp[i - 1][j - 1] + 1 (for replacement));
  2. Delete word1[i - 1] and word1[0..i - 2] = word2[0..j - 1] (dp[i][j] = dp[i - 1][j] + 1 (for deletion));
  3. Insert word2[j - 1] to word1[0..i - 1] and word1[0..i - 1] + word2[j - 1] = word2[0..j - 1] (dp[i][j] = dp[i][j - 1] + 1 (for insertion)).

Make sure you understand the subtle differences between the equations for deletion and insertion. For deletion, we are actually converting word1[0..i - 2] to word2[0..j - 1], which costs dp[i - 1][j], and then deleting the word1[i - 1], which costs 1. The case is similar for insertion.

Putting these together, we now have:

  1. dp[i][0] = i;
  2. dp[0][j] = j;
  3. dp[i][j] = dp[i - 1][j - 1], if word1[i - 1] = word2[j - 1];
  4. dp[i][j] = min(dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1, dp[i][j - 1] + 1), otherwise.

The above state equations can be turned into the following code directly.

	public int minDistance(String word1, String word2) {
		int m = word1.length();
		int n = word2.length();
		// 注意长度,字符有0长度
		//dp[i][j] 代表最小操作数(步骤),从 word1[0..i-1]转化为 word2[0..j-1].
		int[][] dp = new int[m + 1][n + 1];
		// dp[i][0]=i表示,字符长度为i变为长度0,delete i个子符,需要i步
		// dp[0][i]=i表示,字符长度为0变为长度i,insert i个子符,需要i步
		for (int i = 0; i <= m; i++)
			dp[i][0] = i;
		for (int i = 0; i <= n; i++)
			dp[0][i] = i;
		//注意<=
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= n; j++) {
				//如果前i-1
				if (word1.charAt(i - 1) == word2.charAt(j - 1))
					dp[i][j] = dp[i - 1][j - 1];
				else
					dp[i][j] = 1 + 
					Math.min(dp[i - 1][j - 1], 
							Math.min(dp[i][j - 1], dp[i - 1][j]));
			}

		return dp[m][n];
	}
从0开始

   public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        
        int[][] cost = new int[m + 1][n + 1];
        for(int i = 0; i <= m; i++)
            cost[i][0] = i;
        for(int i = 1; i <= n; i++)
            cost[0][i] = i;
        
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(word1.charAt(i) == word2.charAt(j))
                    cost[i + 1][j + 1] = cost[i][j];
                else {
                    int a = cost[i][j];
                    int b = cost[i][j + 1];
                    int c = cost[i + 1][j];
                    cost[i + 1][j + 1] = a < b ? (a < c ? a : c) : (b < c ? b : c);
                    cost[i + 1][j + 1]++;
                }
            }
        }
        return cost[m][n];
    }
dfs+记忆搜索算法
	public int minDistance(String word1, String word2) {
		int m = word1.length();
		int n = word2.length();
		int[][] cache = new int[m + 1][n + 1];
		return minDistance(word1, 0, word2, 0, cache);
	}

	private int minDistance(String word1, int a, String word2, int b, int[][] cache) {
		if (a == word1.length() && b == word2.length())
			return 0;
		if (a == word1.length())
			return word2.length() - b;
		
		if (b == word2.length())
			return word1.length() - a;
		
		if (cache[a][b] != 0)
			return cache[a][b];
		
		if (word1.charAt(a) == word2.charAt(b))
			return cache[a][b] = 
			minDistance(word1, a + 1, word2, b + 1, cache);
		
		else
			return cache[a][b] = 
			Math.min(Math.min
			(minDistance(word1, a + 1, word2, b + 1, cache),
			minDistance(word1, a, word2, b + 1, cache)), 
			minDistance(word1, a + 1, word2, b, cache))
					+ 1;
	}

https://discuss.leetcode.com/topic/17639/20ms-detailed-explained-c-solutions-o-n-space

参考discuss:https://discuss.leetcode.com/topic/20922/java-dp-solution-o-nm
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值