6
6
if they are one edit (or zero edits) away.
7
7
"""
8
8
import unittest
9
- import collections
10
9
from typing import Callable
11
10
12
11
@@ -18,27 +17,43 @@ def one_away(s1: str, s2: str) -> bool:
18
17
2. remove a character
19
18
3. replace a character
20
19
Zero edits away means the two strings are exactly the same.
21
- We will analyze character frequencies to detect anomalies.
22
- An anomaly can be any of the 3 types of edits.
23
- Runtime: O(n + m), where n is length of s1 and m is length of s2
24
- Space Complexity: O(n + m)
20
+ We will do different checks depending on the size different of the strings.
21
+ Runtime: O(n), where n is length of s1
22
+ Space Complexity: O(n + n +/- 1) = O(n), where n is length of s1
25
23
:param s1: one string we want to compare
26
24
:param s2: other string to compare
27
25
:return: true if one or zero edits away, false otherwise
28
26
"""
29
- # if size differs by more than 1, guaranteed more than one anomaly .
27
+ # if size differs by more than 1, guaranteed more than one edit distance .
30
28
if abs (len (s1 ) - len (s2 )) > 1 :
31
29
return False
30
+ # if size is the same, scan for edits
31
+ if len (s1 ) == len (s2 ):
32
+ edits = 0
33
+ for i , c in enumerate (s1 ):
34
+ if c == s2 [i ]:
35
+ continue
36
+ edits += 1
37
+ if edits > 1 :
38
+ return False
39
+ return True
40
+ # otherwise, we have an insertion/deletion
41
+ # compare both strings for insertion/deletion
42
+ # want to loop through the shorter string to avoid going out of bounds
43
+ s_short = s1 if len (s1 ) < len (s2 ) else s2
44
+ s_long = s1 if len (s1 ) > len (s2 ) else s2
32
45
33
- char_freqs_s1 = collections .Counter (s1 )
34
- char_freqs_s2 = collections .Counter (s2 )
35
-
36
- anomalies = 0
37
- for key , value in char_freqs_s1 .items ():
38
- if key not in char_freqs_s2 or value != char_freqs_s2 [key ]:
39
- anomalies += 1
40
- if anomalies > 1 :
41
- return False
46
+ addend = 0
47
+ for i , c in enumerate (s_short ):
48
+ if c == s_long [i + addend ]:
49
+ continue
50
+ if i == i + addend :
51
+ # addend is 0, will check next char in next iteration
52
+ addend += 1
53
+ continue
54
+ # otherwise, addend is not 0, and we did not match characters.
55
+ # guaranteed at least 2 edit distance
56
+ return False
42
57
return True
43
58
44
59
@@ -56,6 +71,8 @@ def _run_tests(self, f: Callable[[str, str], bool]) -> None:
56
71
("a" , "b" , True ),
57
72
("" , "" , True ),
58
73
("pale" , "elap" , False ),
74
+ ("pale" , "elaps" , False ),
75
+ ("pale" , "palse" , True )
59
76
]
60
77
for s1 , s2 , expected in cases :
61
78
self .assertEqual (f (s1 , s2 ), expected , msg = (s1 , s2 ))
0 commit comments