(LeetCode 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
题目:
给定两个字符串,求把S变成T所需的最小操作数。
3种字符操作分别为插入、删除、替换。
思路:
动态规划思想:
假设dp[i][j]表示以S[i]结尾的字符串和以T[j]结尾的字符串转换所需的最小操作数,考虑三种操作,然后取三者最小值:
1、替换:
假设S[i-1],T[j-1]已对齐,即dp[i-1][j-1]已知,则当S[i]==T[j]时,dp[i][j]=dp[i-1][j-1],否则,dp[i][j]=dp[i-1][j-1]+1.
2、删除
假设S[i-1],T[j]已对齐,即dp[i-1][j]已知,多出来的S[i]需删除,操作数+1,则dp[i][j]=dp[i-1][j]+1.
3、插入
假设S[i],T[j-1]已对齐,即dp[i][j-1]已知,需在S中插入S[i+1]=T[j]来匹配,操作数+1,则dp[i][j]=dp[i][j-1]+1.
状态转移方程:
dp[i][j]=min(dp[i-1][j-1]+(S[i]==T[j]?0,1),dp[i-1][j]+1,dp[i][j-1]+1)
初始值:
dp[i][0]=i
dp[0][j]=j
复杂度:
时间复杂度:O(m*n)
空间复杂度:O(m*n)
空间优化:
由状态转移方程可知,dp[i][j]与dp[i-1][j-1],dp[i-1][j],dp[i][j-1]有关,可以去掉一维,只留下dp[j]。
等式右边的dp[i-1][j]和dp[i][j-1]都可以直接改成dp[j](旧的值)和dp[j-1](已更新),只有dp[i-1][j-1]没有记录下来,通过某个变量保存起来之后就可以。
因此空间复杂度:O(n)
代码:
class Solution { public: int minDistance(string word1, string word2) { int m=word1.length(); int n=word2.length(); vector<vector<int> > distance(m+1,vector<int>(n+1)); for(int i=0;i<=m;i++){ for(int j=0;j<=n;j++){ if(0==i){ distance[i][j]=j; } else if(0==j){ distance[i][j]=i; } else{ distance[i][j]=min(distance[i-1][j-1]+((word1[i-1]==word2[j-1])?0:1), min(distance[i-1][j]+1,distance[i][j-1]+1) ); } } } return distance[m][n]; } };
class Solution { public: int minDistance(string word1, string word2) { int m=word1.length(); int n=word2.length(); vector<int> distance(n+1); for(int i=0;i<=m;i++){ int last; for(int j=0;j<=n;j++){ if(0==i){ distance[j]=j; } else if(0==j){ last=distance[j]; distance[j]=i; } else{ int temp=distance[j]; distance[j]=min(last+((word1[i-1]==word2[j-1])?0:1), min(distance[j]+1,distance[j-1]+1) ); last=temp; } } } return distance[n]; } };