题目地址:
https://leetcode.com/problems/one-edit-distance/
给定两个字符串
s
s
s和
t
t
t,问
s
s
s可否由下列三种变换变为
t
t
t:
1、在
s
s
s中插入一个字符;
2、在
s
s
s中删除一个字符;
3、在
s
s
s中替换一个字符。
如果可以就返回true,否则返回false。
首先排除掉 s s s与 t t t长度差大于等于 2 2 2或者 s s s和 t t t相等的情况,这两种情况下 s s s都是不可能变为 t t t的,直接返回false。
接着,从左向右同时扫描 s s s和 t t t,如果遇到相同字符,那就继续扫描,否则,如果遇到不同字符,那么 s s s必然要经过三种变换其中的一种,来”修复“这种不同,而用哪一种变换取决于 s s s和 t t t的长度的比较。如果 s s s和 t t t一样长,那就是变换 3 3 3,如果 s s s比 t t t长,那就是变换 2 2 2,如果 s s s比 t t t短,那就是变换 1 1 1;无论哪一种,都只需要继续比较 s s s和 t t t的剩余子串就可以了。代码如下:
public class Solution {
public boolean isOneEditDistance(String s, String t) {
// 如果两个字符串长度之差大于等于2,或者两个字符串相等,
// 那s绝对无法通过一次变换变为t,直接返回false
if (Math.abs(s.length() - t.length()) >= 2 || s.equals(t)) {
return false;
}
int i = 0, j = 0;
while (i < s.length() && j < t.length() && s.charAt(i) == t.charAt(j)) {
i++;
j++;
}
if (s.length() < t.length()) {
return s.substring(i).equals(t.substring(j + 1));
} else if (s.length() > t.length()) {
return s.substring(i + 1).equals(t.substring(j));
} else {
return s.substring(i + 1).equals(t.substring(j + 1));
}
}
}
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。
算法正确性证明:
首先如果两个字符串长度大于
1
1
1或者两个字符串相等的时候,返回false,这一点没有问题。
接下来,当while循环退出时,有三种可能性,
1、
i
i
i已经走到头;
2、
j
j
j已经走到头;
3、
s
[
i
]
≠
t
[
j
]
s[i]\ne t[j]
s[i]=t[j]。
如果
s
s
s的长度小于
t
t
t的话,那么要么
1
1
1要么
3
3
3,并且
t
t
t的长度比
s
s
s大
1
1
1;如果是
1
1
1,那么说明
t
[
j
+
1
,
.
.
.
]
t[j+1,...]
t[j+1,...]应该是空串,也就是
t
t
t删去最后一个字母应该会变成
s
s
s;如果是
3
3
3,那么就要把
s
s
s在
i
i
i的位置新加一个字母,接着比
s
s
s之后的子串和
t
[
j
+
1
,
.
.
.
]
t[j+1,...]
t[j+1,...]是否相等。无论怎样,都可以写为return s.substring(i).equals(t.substring(j + 1));
;
如果
s
s
s的长度大于
t
t
t的话,证明是类似的;至于两者长度相等时的证明是显然的。综上,算法正确。