Skip to content

Commit 475b8e8

Browse files
authored
Merge pull request #22 from miguelHx/miguel_1.5_one_away
Miguel 1.5 - One Away [Python]
2 parents 21e7165 + 97c01c2 commit 475b8e8

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"""
2+
Python version 3.7.0
3+
1.5 - One Away
4+
There are three types of edits that can be performed on strings: insert a character,
5+
remove a character, or replace a character. Given two strings, write a function to check
6+
if they are one edit (or zero edits) away.
7+
"""
8+
import unittest
9+
from typing import Callable
10+
11+
12+
def one_away(s1: str, s2: str) -> bool:
13+
"""
14+
Checks if two strings are one edit or zero edits away.
15+
There are 3 types of edits:
16+
1. insert a character
17+
2. remove a character
18+
3. replace a character
19+
Zero edits away means the two strings are exactly the same.
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
23+
:param s1: one string we want to compare
24+
:param s2: other string to compare
25+
:return: true if one or zero edits away, false otherwise
26+
"""
27+
# if size differs by more than 1, guaranteed more than one edit distance.
28+
if abs(len(s1) - len(s2)) > 1:
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
45+
46+
added = 0
47+
for i, c in enumerate(s_short):
48+
if c == s_long[i + added]:
49+
continue
50+
# chars didn't match, will check next char in next iteration
51+
added += 1
52+
if added > 1:
53+
# added more than once, and we did not match characters.
54+
# guaranteed at least 2 edit distance
55+
return False
56+
return True
57+
58+
59+
class TestOneAwayFunction(unittest.TestCase):
60+
def _run_tests(self, f: Callable[[str, str], bool]) -> None:
61+
cases = [
62+
("pale", "ple", True),
63+
("pales", "pale", True),
64+
("pale", "bale", True),
65+
("pale", "bake", False),
66+
("", "swag", False),
67+
("paale", "pale", True),
68+
("a", "", True),
69+
("", "b", True),
70+
("a", "b", True),
71+
("", "", True),
72+
("pale", "elap", False),
73+
("pale", "elaps", False),
74+
("pale", "palse", True)
75+
]
76+
for s1, s2, expected in cases:
77+
self.assertEqual(f(s1, s2), expected, msg=(s1, s2))
78+
79+
def test_one_away(self):
80+
self._run_tests(one_away)
81+
82+
83+
if __name__ == '__main__':
84+
unittest.main()

0 commit comments

Comments
 (0)