One Away:字符串有3种编辑操作,分别是插入、删除和替换。判断两个字符串是否可以通过一次编辑互相转换。
可以使用暴力搜索的方法,将和某一个字符串编辑距离为1的所有字符串枚举出来,然后再比较,也就是说用其余字符替换每一个字符,插入每一个可能的字符。
但是这种方法太慢了,这里就不实现了。
可以从3种操作的特点入手来解决这道题:
- 替换操作,本质上就是两个等长的字符串只有一个位置的字符不同
- 插入操作,两个长度差
1的字符串,某一个子序列是相同的,然后短字符串后面的部分右移和长字符串后面的部分相同 - 删除操作,可以看做插入的逆
根据以上特征,可以写出如下代码:
class Solution {
public:
bool oneEditAway(string first, string second) {
if(first.size() == second.size()){
return oneEditReplace(first, second);
}
else if(first.size() + 1 == second.length()){
return oneEditInsert(first, second);
}
else if(second.size() + 1 == first.length()){
return oneEditInsert(second, first);
}
else return false;
}
private:
bool oneEditReplace(const string &s1, const string &s2)
{
bool bDiff = false;
for(size_t i = 0; i < s1.size(); i++)
{
if(s1[i] != s2[i]){
if(bDiff) return false;
else bDiff = true;
}
}
return true;
}
bool oneEditInsert(const string &shorter, const string longer)
{
bool bInsert = false;
for(size_t i = 0, j = 0; i < shorter.size() && j < longer.size(); i++, j++)
{
if(shorter[i] != longer[j]){
if(bInsert) return false;
else{
bInsert = true;
i--;
}
}
}
return true;
}
};
时间复杂度为O(n),n表示较短字符串的长度。
通过观察可以发现oneEditReplace()和oneEditInsert()的代码非常像:依次比较每一个字符,确保只有一个位置上的字符是不同的,对不同的字符进行不同的处理。oneEditReplace()翻转标志位,而oneEditInsert()保持短字符串的索引不变,只递增长字符串的索引,所以我们可以对代码合并。
class Solution {
public:
bool oneEditAway(string first, string second) {
const string &shorter = first.size() <= second.size() ? first : second;
const string &longer = first.size() <= second.size() ? second : first;
if(longer.size() - shorter.size() > 1) return false;
bool bDiff = false;
for(size_t i = 0, j = 0; i < shorter.size() && j < longer.size(); i++, j++)
{
if(shorter[i] != longer[j]){
if(bDiff) return false;
else{
bDiff = true;
if(longer.size() != shorter.size()){
i--;
}
}
}
}
return true;
}
};
虽然合并后的代码易读性变差,但是更加紧凑。
1091

被折叠的 条评论
为什么被折叠?



