From 603f184c61b7b1ade989e508b5e7838ea9d016fd Mon Sep 17 00:00:00 2001 From: Sean Leishman Date: Sat, 24 Jun 2023 18:39:34 +0100 Subject: [PATCH] update folder structure --- algorithms/Python/README.md | 17 +++++- .../levenshtein_distance.py | 56 +++++++------------ .../levenshtein_distance_dp.py | 27 --------- .../Python/recursion/levenshtein_distance.py | 41 ++++++++++++++ 4 files changed, 77 insertions(+), 64 deletions(-) delete mode 100644 algorithms/Python/dynamic_programming/levenshtein_distance_dp.py create mode 100644 algorithms/Python/recursion/levenshtein_distance.py diff --git a/algorithms/Python/README.md b/algorithms/Python/README.md index 56e61288..e2572c59 100644 --- a/algorithms/Python/README.md +++ b/algorithms/Python/README.md @@ -1,6 +1,7 @@ # Python ## Arrays + - [Count Inversions](arrays/counting_inversions.py) - [Majority Element](arrays/majority_element.py) - [Rotate Array](arrays/rotate_array.py) @@ -10,31 +11,36 @@ - [Max Sub Array Sum](arrays/max_sub_array_sum.py) ## Linked Lists + - [Doubly](linked_lists/doubly.py) - [Singly](linked_lists/singly.py) - [Reverse List](linked_lists/reverse-linkedlist.py) - [Middle Node](linked_lists/middle-node-linkedlist.py) - [Cycle Detection and Removal](linked_lists/cycle-detection-and-removal-linkedlist.py) - ## Dictionaries + - [Two Sum](dictionaries/two-sum.py) ## Multiplication + - [Karatsuba](multiplication/karatsuba_algorithm.py) ## Recursion + - [Factorial](recursion/factorial.py) - [n-th Fibonacci number](recursion/nth_fibonacci_number.py) - [Recursive Insertion Sort](recursion/recursive_insertion_sort.py) - [Recursive Sum of n numbers](recursion/recursive-sum-of-n-numbers.py) - [GCD by Euclid's Algorithm](recursion/gcd_using_recursion.py) - +- [Levenshtein distance](recursion/levenshtein_distance.py) ## Scheduling + - [Interval Scheduling](scheduling/interval_scheduling.py) ## Searching + - [Binary Search](searching/binary_search.py) - [Jump Search](searching/jump_search.py) - [Linear Search](searching/linear_search.py) @@ -44,6 +50,7 @@ - [Breath First Search](searching/breadth-first-search.py) ## Sorting + - [Bubble Sort](sorting/bubble_sort.py) - [Comb Sort](sorting/comb_sort.py) - [Count Sort](sorting/count-sort.py) @@ -56,6 +63,7 @@ - [Merge sort](sorting/merge_sort.py) ## Strings + - [Is Good Str](strings/is_good_str.py) - [Palindrome](strings/palindrome.py) - [Word Count](strings/word_count.py) @@ -69,6 +77,7 @@ - [Roman to Int](strings/roman-to-int.py) ## Dynamic Programming + - [Print Fibonacci Series Up To N-th Term](dynamic_programming/fibonacci_series.py) - [Sum Up To N-th Term Of Fibonacci Series](dynamic_programming/fibonacci_series_sum.py) - [N-th Term Of Fibonacci Series](dynamic_programming/fibonacci_series_nth_term.py) @@ -77,16 +86,20 @@ - [Levenshtein distance](dynamic_programming/levenshtein_distance.py) ## Graphs + - [Simple Graph](graphs/graph.py) - [BFS SEQUENCE](graphs/bfs-sequence.py) - [Depth First Search](graphs/depth-first-search.py) ## Trees + - [Binary Tree](trees/binary_tree.py) - [Binary Search Tree](trees/binary_search_tree.py) ## Queues + - [First in First out Queue](queues/fifo-queue.py) ## Number Theory + - [Prime Number Checker](number_theory/prime_number.py) diff --git a/algorithms/Python/dynamic_programming/levenshtein_distance.py b/algorithms/Python/dynamic_programming/levenshtein_distance.py index 58e568a8..19ebc26c 100644 --- a/algorithms/Python/dynamic_programming/levenshtein_distance.py +++ b/algorithms/Python/dynamic_programming/levenshtein_distance.py @@ -1,41 +1,27 @@ -# The Levenshtein distance (Edit distance) Problem -# Informally, the Levenshtein distance between two words is -# the minimum number of single-character edits (insertions, deletions or substitutions) -# required to change one word into the other. +def edit_distance(w1, w2): + """ + Find edit distance (minimum number of changes) required to convert string w1 to string w2. + """ -# For example, the Levenshtein distance between kitten and sitting is 3. -# The minimal edit script that transforms the former into the latter is: + m = [[0 if x != 0 else y if y != 0 else x for x in range(len(w2) + 1)] for y in range(len(w1) + 1)] -# kitten —> sitten (substitution of s for k) -# sitten —> sittin (substitution of i for e) -# sittin —> sitting (insertion of g at the end) + for i in range(1,len(w1) + 1): + m[i][0] = i + for j in range(1, len(w2) + 1): + m[0][j] = j + + for i in range(1, len(w1) + 1): + for j in range(1, len(w2) + 1): + m[i][j] = min( + m[i-1][j-1] + int(w1[i-1] != w2[j-1]), + m[i-1][j] + 1, + m[i][j-1] + 1 + ) + + return m -def levenshtein_distance(word_1, chars_1, word_2, chars_2): - # base case if the strings are empty - if chars_1 == 0: - return chars_2 - if chars_2 == 0: - return chars_1 - # if last characters of the string match, the cost of - # operations is 0, i.e. no changes are made - if word_1[chars_1 - 1] == word_2[chars_2 - 1]: - cost = 0 - else: - cost = 1 +if __name__ == "__main__": + print(edit_distance("sitting", "kitten")) - # calculating the numbers of operations recursively - deletion = levenshtein_distance(word_1, chars_1 - 1, word_2, chars_2) + 1 - insertion = levenshtein_distance(word_1, chars_1, word_2, chars_2 - 1) + 1 - substitution = levenshtein_distance(word_1, chars_1 - 1, word_2, chars_2 - 1) + cost - - return min(deletion, insertion, substitution) - -# driving script -if __name__ == '__main__': - word_1 = 'plain' - word_2 = 'plane' - - print('The Levenshtein distance is:') - print(levenshtein_distance(word_1, len(word_1), word_2, len(word_2))) diff --git a/algorithms/Python/dynamic_programming/levenshtein_distance_dp.py b/algorithms/Python/dynamic_programming/levenshtein_distance_dp.py deleted file mode 100644 index 19ebc26c..00000000 --- a/algorithms/Python/dynamic_programming/levenshtein_distance_dp.py +++ /dev/null @@ -1,27 +0,0 @@ - -def edit_distance(w1, w2): - """ - Find edit distance (minimum number of changes) required to convert string w1 to string w2. - """ - - m = [[0 if x != 0 else y if y != 0 else x for x in range(len(w2) + 1)] for y in range(len(w1) + 1)] - - for i in range(1,len(w1) + 1): - m[i][0] = i - for j in range(1, len(w2) + 1): - m[0][j] = j - - for i in range(1, len(w1) + 1): - for j in range(1, len(w2) + 1): - m[i][j] = min( - m[i-1][j-1] + int(w1[i-1] != w2[j-1]), - m[i-1][j] + 1, - m[i][j-1] + 1 - ) - - return m - - -if __name__ == "__main__": - print(edit_distance("sitting", "kitten")) - diff --git a/algorithms/Python/recursion/levenshtein_distance.py b/algorithms/Python/recursion/levenshtein_distance.py new file mode 100644 index 00000000..58e568a8 --- /dev/null +++ b/algorithms/Python/recursion/levenshtein_distance.py @@ -0,0 +1,41 @@ +# The Levenshtein distance (Edit distance) Problem + +# Informally, the Levenshtein distance between two words is +# the minimum number of single-character edits (insertions, deletions or substitutions) +# required to change one word into the other. + +# For example, the Levenshtein distance between kitten and sitting is 3. +# The minimal edit script that transforms the former into the latter is: + +# kitten —> sitten (substitution of s for k) +# sitten —> sittin (substitution of i for e) +# sittin —> sitting (insertion of g at the end) + +def levenshtein_distance(word_1, chars_1, word_2, chars_2): + # base case if the strings are empty + if chars_1 == 0: + return chars_2 + if chars_2 == 0: + return chars_1 + + # if last characters of the string match, the cost of + # operations is 0, i.e. no changes are made + if word_1[chars_1 - 1] == word_2[chars_2 - 1]: + cost = 0 + else: + cost = 1 + + # calculating the numbers of operations recursively + deletion = levenshtein_distance(word_1, chars_1 - 1, word_2, chars_2) + 1 + insertion = levenshtein_distance(word_1, chars_1, word_2, chars_2 - 1) + 1 + substitution = levenshtein_distance(word_1, chars_1 - 1, word_2, chars_2 - 1) + cost + + return min(deletion, insertion, substitution) + +# driving script +if __name__ == '__main__': + word_1 = 'plain' + word_2 = 'plane' + + print('The Levenshtein distance is:') + print(levenshtein_distance(word_1, len(word_1), word_2, len(word_2)))