题目描述
描述:字符串有三种编辑操作:插入一个英文字符、删除一个英文字符或者替换一个英文字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。
输入:
first = "pale"
second = "ple"
输出: True
输入:
first = "pales"
second = "pal"
输出: False
解题思路
思路1:最直观的想法是,动态规划系列编辑距离问题,判断编辑距离是否小于等于1。其中dp[i][j]表示以first[i-1]结尾转换为以second[j-1]结尾所需的最少次数,其递推公式为:如果first[i-1]=second[j-1],则dp[i][j]=dp[i-1][j-1],反之不相等则dp[i][j]=min({dp[i][j-1],dp[i-1][j],dp[i-1][j-1]})+1。
bool oneEditAway(string first, string second) {
int n1=first.size();
int n2=second.size();
//dp[i][j]表示first[i-1]变成second[j-1]次数
vector<vector<int>> dp(n1+1,vector<int>(n2+1,0));
// second为空串
for(int i=0;i<n1;i++) dp[i][0]=i;
// first为空串
for(int i=0;i<n2;i++) dp[0][i]=i;
for(int i=1;i<=n1;i++)
{
for(int j=1;j<=n2;j++)
{
if(first[i-1]==second[j-1])
dp[i][j]=dp[i-1][j-1];
else
dp[i][j]=min({dp[i][j-1],dp[i-1][j],dp[i-1][j-1]})+1;
}
}
return dp[n1][n2]<=1;
}
思路2:假设first长度为n1,second长度为n2,则一次编辑有三种情况:第一种是n1=n2,即first需要替换一个字符才能变成second;第二种是n1-n2=1,即first需要删除一个字符才能变成second;第三种是n2-n1=1,即first需要添加一个字符才能变成second;零次编辑有一种情况:即n1=n2且first与second完全相同。首先计算first和second的长度,并根据两者之间的长度关系来进行相应的处理。如果两者长度相同,则遍历字符串并逐个比较当前元素,再记录不同元素的个数,如果其大于1,则不可以一次编辑完成,反之可以;如果两者长度相差为1,则记录长串为longer,记录短串为shorter,使用双指针遍历两个字符串,如果相同则两个指针均后移,反之只将长串指针后移,如果长串与短串指针相差大于1,则不可以一次编辑完成,反之可以。
// 不可以处理长度相同的两个字符串 ab和bc无法判断
bool oneInsert(string longer,string shorter)
{
int n1=longer.size();
int n2=shorter.size();
int index1=0;
int index2=0;
while(index1<n1&&index2<n2)
{
// 相等两者均后移
if(longer[index1]==shorter[index2])
{
index1++;
index2++;
}
// 不相等长串后移
else
index1++;
// 相差大于1不可以一次编辑
if(index1-index2>1)
return false;
}
return true;
}
bool oneEditAway(string first, string second)
{
int n1=first.size();
int n2=second.size();
// 长度相差大于1则不可以一次编辑完成
if(abs(n1-n2)>1) return false;
int diff=n1-n2;
// 删除
if(diff==1)
return oneInsert(first,second);
// 增加
else if(diff==-1)
return oneInsert(second,first);
// 替换或者相同 ab bc
int num=0;
for(int i=0;i<n1;i++)
{
if(first[i]!=second[i])
{
num++;
// 有两个或者两个以上不同则不可以一次编辑完成
if(num>1) return false;
}
}
return true;
}