-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathedit_distance.py
154 lines (127 loc) · 4.92 KB
/
edit_distance.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# coding=utf-8
"""
Given two strings str1 and str2 and below operations that can performed on str1.
Find minimum number of edits (operations) required to convert ‘str1’ into ‘str2’
* Insert
* Remove
* Replace
All of the above operations are of equal cost.
Input: str1 = "geek", str2 = "gesek"
Output: 1
We can convert str1 into str2 by inserting a 's'.
Input: str1 = "cat", str2 = "cut"
Output: 1
We can convert str1 into str2 by replacing 'a' with 'u'.
Input: str1 = "sunday", str2 = "saturday"
Output: 3
Last three and first characters are same. We basically
need to convert "un" to "atur". This can be done using
below three operations.
Replace 'n' with 'r', insert t, insert a
"""
import unittest
def min_of_three(first, second, third):
""" Calculates a min of three. parameters should be comparable """
return min(min(first, second), third)
def edit_distance_rec(str1, str2, len1, len2):
"""
Edit Distance Implementation naive approach using recursion
:param str1: first string
:param str2: second string
:param len1: length of str1
:param len2: length of str2
:return: number of operations to be perform in order to transform str1 into str2
:rtype: int
"""
if not len1:
return len2
if not len2:
return len1
if str1[len1-1] == str2[len2-1]:
return edit_distance_rec(str1, str2, len1-1, len2-1)
return 1 + min_of_three(
edit_distance_rec(str1, str2, len1-1, len2), # delete from first
edit_distance_rec(str1, str2, len1, len2-1), # insert into first
edit_distance_rec(str1, str2, len1-1, len2-1) # replace char in first
)
def edit_distance_dp(str1, str2):
"""
Edit Distance Implementation dynamic programming approach
:param str1: first string
:param str2: second string
:return: number of operations to be perform in order to transform str1 into str2
:rtype: int
"""
matrix = [[0 for _ in range(len(str1) + 1)] for _ in range(len(str2) + 1)]
for i in range(len(str1)+1):
matrix[0][i] = i
for i in range(len(str2)+1):
matrix[i][0] = i
for column in range(1, len(str1)+1):
for row in range(1, len(str2)+1):
if str1[column-1] == str2[row-1]:
curry = 0
else:
curry = 1
matrix[row][column] = curry + min_of_three(
matrix[row - 1][column],
matrix[row][column - 1],
matrix[row - 1][column - 1]
)
return matrix[len(str2)][len(str1)]
class TestEditDistance(unittest.TestCase):
""" Test cases for Edit Distance """
def test_edit_distance_rec(self):
""" Test Edit Distance Recursive """
print('==== Test Edit Distance Recursive ====')
str1 = 'sunday'
str2 = 'saturday'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 3)
str1 = ''
str2 = 'test'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 4)
str1 = 'geek'
str2 = 'gesek'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 1)
str1 = 'cat'
str2 = 'cut'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 1)
def test_edit_distance_dp(self):
""" Test Edit Distance DP """
print('==== Test Edit Distance DP ====')
str1 = 'sunday'
str2 = 'saturday'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 3)
str1 = ''
str2 = 'test'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 4)
str1 = 'geek'
str2 = 'gesek'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 1)
str1 = 'cat'
str2 = 'cut'
print('Given strs: {} and {}'.format(str1, str2))
result = edit_distance_rec(str1, str2, len(str1), len(str2))
print('Need to perform {} operations', result)
self.assertEqual(result, 1)