From 3fe1ae2a6750d3697ff63b648aaf525832887f56 Mon Sep 17 00:00:00 2001 From: Victor Encarnacion Date: Wed, 16 May 2018 22:37:54 -0700 Subject: [PATCH 001/302] Add is_rotated.py (#281) * Add tests for is_rotated * Add is_rotated.py * Conforms to PEP8 * Add empty string test to is_rotated --- strings/is_rotated.py | 15 +++++++++++++++ tests/test_strings.py | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 strings/is_rotated.py diff --git a/strings/is_rotated.py b/strings/is_rotated.py new file mode 100644 index 000000000..a68d62d04 --- /dev/null +++ b/strings/is_rotated.py @@ -0,0 +1,15 @@ +""" +Given two strings s1 and s2, determine if s2 is a rotated version of s1. +For example, +is_rotated("hello", "llohe") returns True +is_rotated("hello", "helol") returns False + +accepts two strings +returns bool +""" + +def is_rotated(s1, s2): + if len(s1) == len(s2): + return s2 in s1 + s1 + else: + return False \ No newline at end of file diff --git a/tests/test_strings.py b/tests/test_strings.py index 8cee75bcf..c0aa28334 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -8,6 +8,7 @@ from strings.int_to_roman import int_to_roman from strings.is_palindrome import is_palindrome, is_palindrome_reverse, \ is_palindrome_two_pointer, is_palindrome_stack +from strings.is_rotated import is_rotated from strings.license_number import license_number from strings.make_sentence import make_sentence from strings.merge_string_checker import is_merge_recursive, is_merge_iterative @@ -165,6 +166,22 @@ def test_is_palindrome_stack(self): self.assertFalse(is_palindrome_stack("house")) +class TestIsRotated(unittest.TestCase): + """[summary] + Test for the file is_rotated.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_is_rotated(self): + self.assertTrue(is_rotated("hello", "hello")) + self.assertTrue(is_rotated("hello", "llohe")) + self.assertFalse(is_rotated("hello", "helol")) + self.assertFalse(is_rotated("hello", "lloh")) + self.assertTrue(is_rotated("", "")) + + class TestLicenseNumber(unittest.TestCase): """[summary] Test for the file license_number.py From e84c34422a0956a7fcc9d0fe4bb48b0a1c57878c Mon Sep 17 00:00:00 2001 From: Michael Galarnyk Date: Thu, 17 May 2018 12:02:25 -0700 Subject: [PATCH 002/302] Updated summing_digits to not override a built-in python function (#283) --- maths/summing_digits.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/maths/summing_digits.py b/maths/summing_digits.py index 3f4e21a32..f181a92eb 100644 --- a/maths/summing_digits.py +++ b/maths/summing_digits.py @@ -14,16 +14,16 @@ def sum_dig_pow(a, b): for number in range(a, b + 1): exponent = 1 # set to 1 - sum = 0 # set to 1 + summation = 0 # set to 1 number_as_string = str(number) tokens = list(map(int, number_as_string)) # parse the string into individual digits for k in tokens: - sum = sum + (k ** exponent) + summation = summation + (k ** exponent) exponent += 1 - if sum == number: + if summation == number: result.append(number) return result From 05e38dcf714b5a50844bf45d4d25e4505ca2a6f4 Mon Sep 17 00:00:00 2001 From: Roger Li Date: Wed, 23 May 2018 01:54:58 -0400 Subject: [PATCH 003/302] Update bst.py (#284) --- tree/bst/bst.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tree/bst/bst.py b/tree/bst/bst.py index 223b6b722..de1bddd8c 100644 --- a/tree/bst/bst.py +++ b/tree/bst/bst.py @@ -89,14 +89,14 @@ def preorder(self, root): def inorder(self, root): if root: - self.preorder(root.left) + self.inorder(root.left) print(str(root.data), end = ' ') - self.preorder(root.right) + self.inorder(root.right) def postorder(self, root): if root: - self.preorder(root.left) - self.preorder(root.right) + self.postorder(root.left) + self.postorder(root.right) print(str(root.data), end = ' ') """ From 194500a8963a8528c6eef2637c6edf2b49dda797 Mon Sep 17 00:00:00 2001 From: kangsir Date: Fri, 25 May 2018 00:23:21 +0800 Subject: [PATCH 004/302] update quicksort (#285) * add doc string * when input array type is np.array, output array type is the same rather than list * wrap the sorting function * modified the code according to the pep8 specification * use // instead of int() * add extra 2 argument to pass test * delete two arguments of quick sort and reformat test_sort.py * fix a small bug in quick_sort --- sort/bubble_sort.py | 3 +- sort/comb_sort.py | 4 +-- sort/counting_sort.py | 58 +++++++++++++++++----------------- sort/heap_sort.py | 40 +++++++++++------------ sort/insertion_sort.py | 6 ++-- sort/meeting_rooms.py | 2 +- sort/merge_sort.py | 38 +++++++++++----------- sort/quick_sort.py | 16 +++++++--- sort/selection_sort.py | 2 +- sort/sort_colors.py | 2 +- sort/topsort.py | 18 ++++++----- sort/wiggle_sort.py | 4 ++- tests/test_sort.py | 72 ++++++++++++++++++++++-------------------- 13 files changed, 138 insertions(+), 127 deletions(-) diff --git a/sort/bubble_sort.py b/sort/bubble_sort.py index da9cebdf1..0a8a47063 100644 --- a/sort/bubble_sort.py +++ b/sort/bubble_sort.py @@ -5,8 +5,9 @@ Worst-case performance: O(N^2) """ -def bubble_sort(arr): + +def bubble_sort(arr): def swap(i, j): arr[i], arr[j] = arr[j], arr[i] diff --git a/sort/comb_sort.py b/sort/comb_sort.py index 338771d2b..efa58fc5e 100644 --- a/sort/comb_sort.py +++ b/sort/comb_sort.py @@ -5,11 +5,9 @@ Worst-case performance: O(N^2) """ -from math import floor def comb_sort(arr): - def swap(i, j): arr[i], arr[j] = arr[j], arr[i] @@ -18,7 +16,7 @@ def swap(i, j): shrink = 1.3 sorted = False while not sorted: - gap = int(floor(gap/shrink)) + gap = int(gap / shrink) if gap > 1: sorted = False else: diff --git a/sort/counting_sort.py b/sort/counting_sort.py index 9b11af3cc..46688e218 100644 --- a/sort/counting_sort.py +++ b/sort/counting_sort.py @@ -1,36 +1,36 @@ def counting_sort(arr): - """ + """ Counting_sort - Sorting a array which has no element greater than k - Creating a new temp_arr,where temp_arr[i] contain the number of - element less than or equal to i in the arr + Sorting a array which has no element greater than k + Creating a new temp_arr,where temp_arr[i] contain the number of + element less than or equal to i in the arr Then placing the number i into a correct position in the result_arr - return the result_arr - Complexity: 0(n) - """ + return the result_arr + Complexity: 0(n) + """ - m = min(arr) - #in case there are negative elements, change the array to all positive element - different = 0 - if m < 0: - #save the change, so that we can convert the array back to all positive number - different = -m - for i in range (len(arr)): - arr[i]+= -m - k = max(arr) - temp_arr = [0]*(k+1) - for i in range(0,len(arr)): - temp_arr[arr[i]] = temp_arr[arr[i]]+1 - #temp_array[i] contain the times the number i appear in arr + m = min(arr) + # in case there are negative elements, change the array to all positive element + different = 0 + if m < 0: + # save the change, so that we can convert the array back to all positive number + different = -m + for i in range(len(arr)): + arr[i] += -m + k = max(arr) + temp_arr = [0] * (k + 1) + for i in range(0, len(arr)): + temp_arr[arr[i]] = temp_arr[arr[i]] + 1 + # temp_array[i] contain the times the number i appear in arr - for i in range(1, k+1): - temp_arr[i] = temp_arr[i] + temp_arr[i-1] - #temp_array[i] contain the number of element less than or equal i in arr + for i in range(1, k + 1): + temp_arr[i] = temp_arr[i] + temp_arr[i - 1] + # temp_array[i] contain the number of element less than or equal i in arr - result_arr = [0]*len(arr) - #creating a result_arr an put the element in a correct positon - for i in range(len(arr)-1,-1,-1): - result_arr[temp_arr[arr[i]]-1] = arr[i]-different - temp_arr[arr[i]] = temp_arr[arr[i]]-1 + result_arr = arr.copy() + # creating a result_arr an put the element in a correct positon + for i in range(len(arr) - 1, -1, -1): + result_arr[temp_arr[arr[i]] - 1] = arr[i] - different + temp_arr[arr[i]] = temp_arr[arr[i]] - 1 - return result_arr + return result_arr diff --git a/sort/heap_sort.py b/sort/heap_sort.py index 5cdc78665..6c91cee90 100644 --- a/sort/heap_sort.py +++ b/sort/heap_sort.py @@ -2,7 +2,7 @@ def max_heap_sort(arr): """ Heap Sort that uses a max heap to sort an array in ascending order Complexity: O(n log(n)) """ - for i in range(len(arr)-1,0,-1): + for i in range(len(arr) - 1, 0, -1): max_heapify(arr, i) temp = arr[0] @@ -10,28 +10,26 @@ def max_heap_sort(arr): arr[i] = temp return arr + def max_heapify(arr, end): """ Max heapify helper for max_heap_sort """ - last_parent = int((end-1)/2) + last_parent = (end - 1) // 2 # Iterate from last parent to first - for parent in range(last_parent,-1,-1): + for parent in range(last_parent, -1, -1): current_parent = parent # Iterate from current_parent to last_parent while current_parent <= last_parent: # Find greatest child of current_parent - child = 2*current_parent + 1 - if child + 1 <= end and arr[child] < arr[child+1]: + child = 2 * current_parent + 1 + if child + 1 <= end and arr[child] < arr[child + 1]: child = child + 1 # Swap if child is greater than parent if arr[child] > arr[current_parent]: - temp = arr[current_parent] - arr[current_parent] = arr[child] - arr[child] = temp - + arr[current_parent], arr[child] = arr[child], arr[current_parent] current_parent = child # If no swap occured, no need to keep iterating else: @@ -42,35 +40,35 @@ def min_heap_sort(arr): """ Heap Sort that uses a min heap to sort an array in ascending order Complexity: O(n log(n)) """ - for i in range(0, len(arr)-1): + for i in range(0, len(arr) - 1): min_heapify(arr, i) return arr + def min_heapify(arr, start): """ Min heapify helper for min_heap_sort """ # Offset last_parent by the start (last_parent calculated as if start index was 0) - # All array accesses need to be offet by start - end = len(arr)-1 - last_parent = int((end-start-1)/2) + # All array accesses need to be offset by start + end = len(arr) - 1 + last_parent = (end - start - 1) // 2 # Iterate from last parent to first - for parent in range(last_parent,-1,-1): + for parent in range(last_parent, -1, -1): current_parent = parent # Iterate from current_parent to last_parent while current_parent <= last_parent: # Find lesser child of current_parent - child = 2*current_parent + 1 - if child + 1 <= end-start and arr[child+start] > arr[child+1+start]: + child = 2 * current_parent + 1 + if child + 1 <= end - start and arr[child + start] > arr[ + child + 1 + start]: child = child + 1 # Swap if child is less than parent - if arr[child+start] < arr[current_parent+start]: - temp = arr[current_parent+start] - arr[current_parent+start] = arr[child+start] - arr[child+start] = temp - + if arr[child + start] < arr[current_parent + start]: + arr[current_parent + start], arr[child + start] = \ + arr[child + start], arr[current_parent + start] current_parent = child # If no swap occured, no need to keep iterating else: diff --git a/sort/insertion_sort.py b/sort/insertion_sort.py index 07a0a5265..f6d1ce3c9 100644 --- a/sort/insertion_sort.py +++ b/sort/insertion_sort.py @@ -5,10 +5,10 @@ def insertion_sort(arr): for i in range(len(arr)): cursor = arr[i] pos = i - while pos > 0 and arr[pos-1] > cursor: + while pos > 0 and arr[pos - 1] > cursor: # Swap the number down the list - arr[pos] = arr[pos-1] - pos = pos-1 + arr[pos] = arr[pos - 1] + pos = pos - 1 # Break and do the final swap arr[pos] = cursor diff --git a/sort/meeting_rooms.py b/sort/meeting_rooms.py index 72ebb7d51..2cb60c69a 100644 --- a/sort/meeting_rooms.py +++ b/sort/meeting_rooms.py @@ -16,6 +16,6 @@ def can_attend_meetings(intervals): """ intervals = sorted(intervals, key=lambda x: x.start) for i in range(1, len(intervals)): - if intervals[i].start < intervals[i-1].end: + if intervals[i].start < intervals[i - 1].end: return False return True diff --git a/sort/merge_sort.py b/sort/merge_sort.py index e1b62b337..351a4c5e8 100644 --- a/sort/merge_sort.py +++ b/sort/merge_sort.py @@ -3,34 +3,36 @@ def merge_sort(arr): Complexity: O(n log(n)) """ # Our recursive base case - if len(arr)<= 1: + if len(arr) <= 1: return arr - mid = len(arr)//2 + mid = len(arr) // 2 # Perform merge_sort recursively on both halves - left, right = merge_sort(arr[mid:]), merge_sort(arr[:mid]) + left, right = merge_sort(arr[:mid]), merge_sort(arr[mid:]) # Merge each side together - return merge(left, right) + return merge(left, right, arr.copy()) -def merge(left, right): + +def merge(left, right, merged): """ Merge helper Complexity: O(n) """ - arr = [] - left_cursor, right_cursor = 0,0 + + left_cursor, right_cursor = 0, 0 while left_cursor < len(left) and right_cursor < len(right): # Sort each one and place into the result if left[left_cursor] <= right[right_cursor]: - arr.append(left[left_cursor]) - left_cursor+=1 + merged[left_cursor+right_cursor]=left[left_cursor] + left_cursor += 1 else: - arr.append(right[right_cursor]) - right_cursor+=1 - # Add the left overs if there's any left to the result - for i in range(left_cursor,len(left)): - arr.append(left[i]) - for i in range(right_cursor,len(right)): - arr.append(right[i]) + merged[left_cursor + right_cursor] = right[right_cursor] + right_cursor += 1 + # Add the left overs if there's any left to the result + for left_cursor in range(left_cursor, len(left)): + merged[left_cursor + right_cursor] = left[left_cursor] + # Add the left overs if there's any left to the result + for right_cursor in range(right_cursor, len(right)): + merged[left_cursor + right_cursor] = right[right_cursor] - # Return result - return arr + # Return result + return merged diff --git a/sort/quick_sort.py b/sort/quick_sort.py index ac91d6b49..a262bb4c1 100644 --- a/sort/quick_sort.py +++ b/sort/quick_sort.py @@ -1,17 +1,23 @@ -def quick_sort(arr, first, last): - """ Quicksort +def quick_sort(arr): + """ Quick sort Complexity: best O(n log(n)) avg O(n log(n)), worst O(N^2) """ + return quick_sort_recur(arr, 0, len(arr) - 1) + + +def quick_sort_recur(arr, first, last): if first < last: pos = partition(arr, first, last) # Start our two recursive calls - quick_sort(arr, first, pos-1) - quick_sort(arr, pos+1, last) + quick_sort_recur(arr, first, pos - 1) + quick_sort_recur(arr, pos + 1, last) return arr + + def partition(arr, first, last): wall = first for pos in range(first, last): - if arr[pos] < arr[last]: # last is the pivot + if arr[pos] < arr[last]: # last is the pivot arr[pos], arr[wall] = arr[wall], arr[pos] wall += 1 arr[wall], arr[last] = arr[last], arr[wall] diff --git a/sort/selection_sort.py b/sort/selection_sort.py index fed1c3466..c5db918dd 100644 --- a/sort/selection_sort.py +++ b/sort/selection_sort.py @@ -4,7 +4,7 @@ def selection_sort(arr): """ for i in range(len(arr)): minimum = i - for j in range(i+1, len(arr)): + for j in range(i + 1, len(arr)): # "Select" the correct value if arr[j] < arr[minimum]: minimum = j diff --git a/sort/sort_colors.py b/sort/sort_colors.py index e85879781..aa44e221e 100644 --- a/sort/sort_colors.py +++ b/sort/sort_colors.py @@ -25,6 +25,6 @@ def sort_colors(nums): if __name__ == "__main__": - nums = [0,1,1,1,2,2,2,1,1,1,0,0,0,0,1,1,1,0,0,2,2] + nums = [0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2] sort_colors(nums) print(nums) diff --git a/sort/topsort.py b/sort/topsort.py index bca556d22..8341ce941 100644 --- a/sort/topsort.py +++ b/sort/topsort.py @@ -12,16 +12,16 @@ depGraph = { - "a" : [ "b" ], - "b" : [ "c" ], - "c" : [ 'e'], - 'e' : [ ], - "d" : [ ], - "f" : ["e" , "d"] + "a": ["b"], + "b": ["c"], + "c": ['e'], + 'e': [], + "d": [], + "f": ["e", "d"] } +given = ["b", "c", "a", "d", "e", "f"] -given = [ "b", "c", "a", "d", "e", "f" ] def ret_deps(visited, start): queue = [] @@ -46,7 +46,7 @@ def ret_dep_graph(): if pac in visited: continue visited.add(pac) - #out.append(pac) + # out.append(pac) if pac in depGraph: # find all children for child in depGraph[pac]: @@ -55,4 +55,6 @@ def ret_dep_graph(): out.extend(ret_deps(visited, child)) out.append(pac) print(out) + + ret_dep_graph() diff --git a/sort/wiggle_sort.py b/sort/wiggle_sort.py index 2e09584c3..15dc76d4b 100644 --- a/sort/wiggle_sort.py +++ b/sort/wiggle_sort.py @@ -1,4 +1,6 @@ - +""" +Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3].... +""" def wiggle_sort(nums): for i in range(len(nums)): if (i % 2 == 1) == (nums[i-1] > nums[i]): diff --git a/tests/test_sort.py b/tests/test_sort.py index 3a62d07cd..30f27621c 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -9,42 +9,44 @@ import unittest + class TestSuite(unittest.TestCase): - def test_bubble_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - bubble_sort([1, 5, 65, 23, 57, 1232])) - - def test_comb_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - comb_sort([1, 5, 65, 23, 57, 1232])) - - def test_counting_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - counting_sort([1, 5, 65, 23, 57, 1232])) - self.assertEqual([-1232, -65, -57, -23, -5, -1], - counting_sort([-1, -5, -65, -23, -57, -1232])) - - def test_heap_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - max_heap_sort([1, 5, 65, 23, 57, 1232])) - self.assertEqual([1, 5, 23, 57, 65, 1232], - min_heap_sort([1, 5, 65, 23, 57, 1232])) - - def test_insertion_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - insertion_sort([1, 5, 65, 23, 57, 1232])) - - def test_merge_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - merge_sort([1, 5, 65, 23, 57, 1232])) - - def test_quick_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - quick_sort([1, 5, 65, 23, 57, 1232], 0, 5)) - - def test_selection_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - selection_sort([1, 5, 65, 23, 57, 1232])) + def test_bubble_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + bubble_sort([1, 5, 65, 23, 57, 1232])) + + def test_comb_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + comb_sort([1, 5, 65, 23, 57, 1232])) + + def test_counting_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + counting_sort([1, 5, 65, 23, 57, 1232])) + self.assertEqual([-1232, -65, -57, -23, -5, -1], + counting_sort([-1, -5, -65, -23, -57, -1232])) + + def test_heap_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + max_heap_sort([1, 5, 65, 23, 57, 1232])) + self.assertEqual([1, 5, 23, 57, 65, 1232], + min_heap_sort([1, 5, 65, 23, 57, 1232])) + + def test_insertion_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + insertion_sort([1, 5, 65, 23, 57, 1232])) + + def test_merge_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + merge_sort([1, 5, 65, 23, 57, 1232])) + + def test_quick_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + quick_sort([1, 5, 65, 23, 57, 1232])) + + def test_selection_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + selection_sort([1, 5, 65, 23, 57, 1232])) + if __name__ == "__main__": unittest.main() From a2f55985a4dd8726f1471e0b7aa6e0e346426452 Mon Sep 17 00:00:00 2001 From: keon Date: Fri, 25 May 2018 15:58:57 -0400 Subject: [PATCH 005/302] reorganize arrays --- algorithms/arrays/__init__.py | 13 ++ {arrays => algorithms/arrays}/delete_nth.py | 0 {arrays => algorithms/arrays}/flatten.py | 2 +- {arrays => algorithms/arrays}/garage.py | 0 .../arrays/josephus.py | 0 .../arrays}/longest_non_repeat.py | 4 +- .../arrays}/merge_intervals.py | 2 +- .../arrays}/missing_ranges.py | 0 .../arrays/move_zeros.py | 0 {arrays => algorithms/arrays}/plus_one.py | 2 +- .../arrays/rotate.py | 0 .../arrays/summarize_ranges.py | 2 +- {arrays => algorithms/arrays}/three_sum.py | 0 {arrays => algorithms/arrays}/two_sum.py | 0 arrays/__init__.py | 0 tests/test_array.py | 127 +++++++++++------- 16 files changed, 94 insertions(+), 58 deletions(-) create mode 100644 algorithms/arrays/__init__.py rename {arrays => algorithms/arrays}/delete_nth.py (100%) rename {arrays => algorithms/arrays}/flatten.py (94%) rename {arrays => algorithms/arrays}/garage.py (100%) rename arrays/josephus_problem.py => algorithms/arrays/josephus.py (100%) rename {arrays => algorithms/arrays}/longest_non_repeat.py (94%) rename {arrays => algorithms/arrays}/merge_intervals.py (98%) rename {arrays => algorithms/arrays}/missing_ranges.py (100%) rename arrays/move_zeros_to_end.py => algorithms/arrays/move_zeros.py (100%) rename {arrays => algorithms/arrays}/plus_one.py (97%) rename arrays/rotate_array.py => algorithms/arrays/rotate.py (100%) rename arrays/summary_ranges.py => algorithms/arrays/summarize_ranges.py (95%) rename {arrays => algorithms/arrays}/three_sum.py (100%) rename {arrays => algorithms/arrays}/two_sum.py (100%) delete mode 100644 arrays/__init__.py diff --git a/algorithms/arrays/__init__.py b/algorithms/arrays/__init__.py new file mode 100644 index 000000000..04afdb2f9 --- /dev/null +++ b/algorithms/arrays/__init__.py @@ -0,0 +1,13 @@ +from .delete_nth import * +from .flatten import * +from .garage import * +from .josephus import * +from .longest_non_repeat import * +from .merge_intervals import * +from .missing_ranges import * +from .move_zeros import * +from .plus_one import * +from .rotate import * +from .summarize_ranges import * +from .three_sum import * +from .two_sum import * diff --git a/arrays/delete_nth.py b/algorithms/arrays/delete_nth.py similarity index 100% rename from arrays/delete_nth.py rename to algorithms/arrays/delete_nth.py diff --git a/arrays/flatten.py b/algorithms/arrays/flatten.py similarity index 94% rename from arrays/flatten.py rename to algorithms/arrays/flatten.py index 2b047461a..f2eba48fe 100644 --- a/arrays/flatten.py +++ b/algorithms/arrays/flatten.py @@ -26,6 +26,6 @@ def flatten_iter(iterable): """ for element in iterable: if isinstance(element, Iterable): - yield from flatten(element) + yield from flatten_iter(element) else: yield element diff --git a/arrays/garage.py b/algorithms/arrays/garage.py similarity index 100% rename from arrays/garage.py rename to algorithms/arrays/garage.py diff --git a/arrays/josephus_problem.py b/algorithms/arrays/josephus.py similarity index 100% rename from arrays/josephus_problem.py rename to algorithms/arrays/josephus.py diff --git a/arrays/longest_non_repeat.py b/algorithms/arrays/longest_non_repeat.py similarity index 94% rename from arrays/longest_non_repeat.py rename to algorithms/arrays/longest_non_repeat.py index 43f2055ed..e97efcca0 100644 --- a/arrays/longest_non_repeat.py +++ b/algorithms/arrays/longest_non_repeat.py @@ -10,7 +10,7 @@ """ -def longest_non_repeat(string): +def longest_non_repeat_v1(string): """ Finds the length of the longest substring without repeating characters. @@ -27,7 +27,7 @@ def longest_non_repeat(string): return max_len -def longest_non_repeat_two(string): +def longest_non_repeat_v2(string): """ Finds the length of the longest substring without repeating characters. diff --git a/arrays/merge_intervals.py b/algorithms/arrays/merge_intervals.py similarity index 98% rename from arrays/merge_intervals.py rename to algorithms/arrays/merge_intervals.py index 606ca3427..ee9ce6053 100644 --- a/arrays/merge_intervals.py +++ b/algorithms/arrays/merge_intervals.py @@ -64,7 +64,7 @@ def print_intervals(intervals): print("".join(res)) -def merge_v2(intervals): +def merge_intervals(intervals): """ Merges intervals in the form of list. """ if intervals is None: return None diff --git a/arrays/missing_ranges.py b/algorithms/arrays/missing_ranges.py similarity index 100% rename from arrays/missing_ranges.py rename to algorithms/arrays/missing_ranges.py diff --git a/arrays/move_zeros_to_end.py b/algorithms/arrays/move_zeros.py similarity index 100% rename from arrays/move_zeros_to_end.py rename to algorithms/arrays/move_zeros.py diff --git a/arrays/plus_one.py b/algorithms/arrays/plus_one.py similarity index 97% rename from arrays/plus_one.py rename to algorithms/arrays/plus_one.py index 9edb02fa5..d5bf347f6 100644 --- a/arrays/plus_one.py +++ b/algorithms/arrays/plus_one.py @@ -7,7 +7,7 @@ """ -def plus_one(digits): +def plus_one_v1(digits): """ :type digits: List[int] :rtype: List[int] diff --git a/arrays/rotate_array.py b/algorithms/arrays/rotate.py similarity index 100% rename from arrays/rotate_array.py rename to algorithms/arrays/rotate.py diff --git a/arrays/summary_ranges.py b/algorithms/arrays/summarize_ranges.py similarity index 95% rename from arrays/summary_ranges.py rename to algorithms/arrays/summarize_ranges.py index 3ee3417f2..8cfba68e1 100644 --- a/arrays/summary_ranges.py +++ b/algorithms/arrays/summarize_ranges.py @@ -6,7 +6,7 @@ """ -def summary_ranges(array): +def summarize_ranges(array): """ :type array: List[int] :rtype: List[] diff --git a/arrays/three_sum.py b/algorithms/arrays/three_sum.py similarity index 100% rename from arrays/three_sum.py rename to algorithms/arrays/three_sum.py diff --git a/arrays/two_sum.py b/algorithms/arrays/two_sum.py similarity index 100% rename from arrays/two_sum.py rename to algorithms/arrays/two_sum.py diff --git a/arrays/__init__.py b/arrays/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_array.py b/tests/test_array.py index acae48393..88cf59173 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -1,16 +1,16 @@ -from arrays.delete_nth import delete_nth, delete_nth_naive -from arrays.flatten import flatten, flatten_iter -from arrays.garage import garage -from arrays.josephus_problem import josephus -from arrays.longest_non_repeat import longest_non_repeat, longest_non_repeat_two -from arrays.merge_intervals import Interval, merge_v2 -from arrays.missing_ranges import missing_ranges -from arrays.move_zeros_to_end import move_zeros -from arrays.plus_one import plus_one, plus_one_v2, plus_one_v3 -from arrays.rotate_array import rotate_v1, rotate_v2, rotate_v3 -from arrays.summary_ranges import summary_ranges -from arrays.three_sum import three_sum -from arrays.two_sum import two_sum +from algorithms.arrays import delete_nth, delete_nth_naive +from algorithms.arrays import flatten, flatten_iter +from algorithms.arrays import garage +from algorithms.arrays import josephus +from algorithms.arrays import longest_non_repeat_v1, longest_non_repeat_v2 +from algorithms.arrays import Interval, merge_intervals +from algorithms.arrays import missing_ranges +from algorithms.arrays import move_zeros +from algorithms.arrays import plus_one_v1, plus_one_v2, plus_one_v3 +from algorithms.arrays import rotate_v1, rotate_v2, rotate_v3 +from algorithms.arrays import summarize_ranges +from algorithms.arrays import three_sum +from algorithms.arrays import two_sum import unittest @@ -37,15 +37,19 @@ class TestDeleteNth(unittest.TestCase): def test_delete_nth_naive(self): - self.assertListEqual(delete_nth_naive([20, 37, 20, 21, 37, 21, 21], n=1), + self.assertListEqual(delete_nth_naive( + [20, 37, 20, 21, 37, 21, 21], n=1), [20, 37, 21]) - self.assertListEqual(delete_nth_naive([1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), + self.assertListEqual(delete_nth_naive( + [1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), [1, 1, 3, 3, 7, 2, 2, 2]) - self.assertListEqual(delete_nth_naive([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=3), + self.assertListEqual(delete_nth_naive( + [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=3), [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]) self.assertListEqual(delete_nth_naive([], n=5), []) - self.assertListEqual(delete_nth_naive([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=0), + self.assertListEqual(delete_nth_naive( + [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=0), []) def test_delete_nth(self): @@ -117,32 +121,35 @@ def test_garage(self): steps, seq = garage(initial, final) self.assertEqual(steps, 4) - self.assertListEqual(seq, [[0, 2, 3, 1, 4], [2, 0, 3, 1, 4], [2, 3, 0, 1, 4], [0, 3, 2, 1, 4]]) + self.assertListEqual(seq, [[0, 2, 3, 1, 4], + [2, 0, 3, 1, 4], + [2, 3, 0, 1, 4], + [0, 3, 2, 1, 4]]) class TestLongestNonRepeat(unittest.TestCase): - def test_longest_non_repeat(self): + def test_longest_non_repeat_v1(self): string = "abcabcbb" - self.assertEqual(longest_non_repeat(string), 3) + self.assertEqual(longest_non_repeat_v1(string), 3) string = "bbbbb" - self.assertEqual(longest_non_repeat(string), 1) + self.assertEqual(longest_non_repeat_v1(string), 1) string = "pwwkew" - self.assertEqual(longest_non_repeat(string), 3) + self.assertEqual(longest_non_repeat_v1(string), 3) - def test_longest_non_repeat_two(self): + def test_longest_non_repeat_v2(self): string = "abcabcbb" - self.assertEqual(longest_non_repeat_two(string), 3) + self.assertEqual(longest_non_repeat_v2(string), 3) string = "bbbbb" - self.assertEqual(longest_non_repeat_two(string), 1) + self.assertEqual(longest_non_repeat_v2(string), 1) string = "pwwkew" - self.assertEqual(longest_non_repeat_two(string), 3) + self.assertEqual(longest_non_repeat_v2(string), 3) class TestMergeInterval(unittest.TestCase): @@ -156,9 +163,9 @@ def test_merge(self): [Interval(1, 6), Interval(8, 10), Interval(15, 18)] ) - def test_merge_v2(self): + def test_merge_intervals(self): interval_list = [[1, 3], [2, 6], [8, 10], [15, 18]] - merged_intervals = merge_v2(interval_list) + merged_intervals = merge_intervals(interval_list) self.assertEqual( merged_intervals, [[1, 6], [8, 10], [15, 18]] @@ -172,7 +179,8 @@ def test_missing_ranges(self): arr = [3, 5, 10, 11, 12, 15, 19] self.assertListEqual(missing_ranges(arr, 0, 20), - [(0, 2), (4, 4), (6, 9), (13, 14), (16, 18), (20, 20)]) + [(0, 2), (4, 4), (6, 9), + (13, 14), (16, 18), (20, 20)]) self.assertListEqual(missing_ranges(arr, 6, 100), [(6, 9), (13, 14), (16, 18), (20, 100)]) @@ -191,64 +199,79 @@ def test_move_zeros(self): class TestPlusOne(unittest.TestCase): - def test_plus_one(self): + def test_plus_one_v1(self): - self.assertListEqual(plus_one([0]), [1]) - self.assertListEqual(plus_one([9]), [1, 0]) - self.assertListEqual(plus_one([1, 0, 9]), [1, 1, 0]) - self.assertListEqual(plus_one([9, 9, 8, 0, 0, 9]), [9, 9, 8, 0, 1, 0]) - self.assertListEqual(plus_one([9, 9, 9, 9]), [1, 0, 0, 0, 0]) + self.assertListEqual(plus_one_v1([0]), [1]) + self.assertListEqual(plus_one_v1([9]), [1, 0]) + self.assertListEqual(plus_one_v1([1, 0, 9]), [1, 1, 0]) + self.assertListEqual(plus_one_v1([9, 9, 8, 0, 0, 9]), + [9, 9, 8, 0, 1, 0]) + self.assertListEqual(plus_one_v1([9, 9, 9, 9]), + [1, 0, 0, 0, 0]) def test_plus_one_v2(self): self.assertListEqual(plus_one_v2([0]), [1]) self.assertListEqual(plus_one_v2([9]), [1, 0]) self.assertListEqual(plus_one_v2([1, 0, 9]), [1, 1, 0]) - self.assertListEqual(plus_one_v2([9, 9, 8, 0, 0, 9]), [9, 9, 8, 0, 1, 0]) - self.assertListEqual(plus_one_v2([9, 9, 9, 9]), [1, 0, 0, 0, 0]) + self.assertListEqual(plus_one_v2([9, 9, 8, 0, 0, 9]), + [9, 9, 8, 0, 1, 0]) + self.assertListEqual(plus_one_v2([9, 9, 9, 9]), + [1, 0, 0, 0, 0]) def test_plus_one_v3(self): self.assertListEqual(plus_one_v3([0]), [1]) self.assertListEqual(plus_one_v3([9]), [1, 0]) self.assertListEqual(plus_one_v3([1, 0, 9]), [1, 1, 0]) - self.assertListEqual(plus_one_v3([9, 9, 8, 0, 0, 9]), [9, 9, 8, 0, 1, 0]) - self.assertListEqual(plus_one_v3([9, 9, 9, 9]), [1, 0, 0, 0, 0]) + self.assertListEqual(plus_one_v3([9, 9, 8, 0, 0, 9]), + [9, 9, 8, 0, 1, 0]) + self.assertListEqual(plus_one_v3([9, 9, 9, 9]), + [1, 0, 0, 0, 0]) class TestRotateArray(unittest.TestCase): def test_rotate_v1(self): - self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=3), [5, 6, 7, 1, 2, 3, 4]) - self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=1), [7, 1, 2, 3, 4, 5, 6]) - self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=7), [1, 2, 3, 4, 5, 6, 7]) + self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=3), + [5, 6, 7, 1, 2, 3, 4]) + self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=1), + [7, 1, 2, 3, 4, 5, 6]) + self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=7), + [1, 2, 3, 4, 5, 6, 7]) self.assertListEqual(rotate_v1([1, 2], k=111), [2, 1]) def test_rotate_v2(self): - self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=3), [5, 6, 7, 1, 2, 3, 4]) - self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=1), [7, 1, 2, 3, 4, 5, 6]) - self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=7), [1, 2, 3, 4, 5, 6, 7]) + self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=3), + [5, 6, 7, 1, 2, 3, 4]) + self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=1), + [7, 1, 2, 3, 4, 5, 6]) + self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=7), + [1, 2, 3, 4, 5, 6, 7]) self.assertListEqual(rotate_v2([1, 2], k=111), [2, 1]) def test_rotate_v3(self): - self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=3), [5, 6, 7, 1, 2, 3, 4]) - self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=1), [7, 1, 2, 3, 4, 5, 6]) - self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=7), [1, 2, 3, 4, 5, 6, 7]) + self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=3), + [5, 6, 7, 1, 2, 3, 4]) + self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=1), + [7, 1, 2, 3, 4, 5, 6]) + self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=7), + [1, 2, 3, 4, 5, 6, 7]) self.assertListEqual(rotate_v3([1, 2], k=111), [2, 1]) class TestSummaryRanges(unittest.TestCase): - def test_summary_ranges(self): + def test_summarize_ranges(self): - self.assertListEqual(summary_ranges([0, 1, 2, 4, 5, 7]), + self.assertListEqual(summarize_ranges([0, 1, 2, 4, 5, 7]), [(0, 2), (4, 5), (7, 7)]) - self.assertListEqual(summary_ranges([-5, -4, -3, 1, 2, 4, 5, 6]), + self.assertListEqual(summarize_ranges([-5, -4, -3, 1, 2, 4, 5, 6]), [(-5, -3), (1, 2), (4, 6)]) - self.assertListEqual(summary_ranges([-2, -1, 0, 1, 2]), + self.assertListEqual(summarize_ranges([-2, -1, 0, 1, 2]), [(-2, 2)]) From dd6567a03af84b3571c0adb7723b13a4fa519b6c Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:07:19 -0700 Subject: [PATCH 006/302] reorganize linkedlist --- algorithms/linkedlist/__init__.py | 8 ++++++++ .../linkedlist}/add_two_numbers.py | 0 .../linkedlist}/copy_random_pointer.py | 0 .../linkedlist}/delete_node.py | 0 .../linkedlist}/first_cyclic_node.py | 0 .../linkedlist}/intersection.py | 0 .../linkedlist}/is_cyclic.py | 0 .../linkedlist}/is_palindrome.py | 0 .../linkedlist}/is_sorted.py | 0 .../linkedlist}/kth_to_last.py | 0 .../linkedlist}/linkedlist.py | 0 .../linkedlist}/merge_two_list.py | 0 .../linkedlist}/partition.py | 0 .../linkedlist}/remove_duplicates.py | 0 .../linkedlist}/remove_range.py | 0 .../linkedlist}/reverse.py | 0 .../linkedlist}/rotate_list.py | 0 .../linkedlist}/swap_in_pairs.py | 0 linkedlist/__init__.py | 0 tests/test_linkedlist.py | 18 ++++++++++-------- 20 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 algorithms/linkedlist/__init__.py rename {linkedlist => algorithms/linkedlist}/add_two_numbers.py (100%) rename {linkedlist => algorithms/linkedlist}/copy_random_pointer.py (100%) rename {linkedlist => algorithms/linkedlist}/delete_node.py (100%) rename {linkedlist => algorithms/linkedlist}/first_cyclic_node.py (100%) rename {linkedlist => algorithms/linkedlist}/intersection.py (100%) rename {linkedlist => algorithms/linkedlist}/is_cyclic.py (100%) rename {linkedlist => algorithms/linkedlist}/is_palindrome.py (100%) rename {linkedlist => algorithms/linkedlist}/is_sorted.py (100%) rename {linkedlist => algorithms/linkedlist}/kth_to_last.py (100%) rename {linkedlist => algorithms/linkedlist}/linkedlist.py (100%) rename {linkedlist => algorithms/linkedlist}/merge_two_list.py (100%) rename {linkedlist => algorithms/linkedlist}/partition.py (100%) rename {linkedlist => algorithms/linkedlist}/remove_duplicates.py (100%) rename {linkedlist => algorithms/linkedlist}/remove_range.py (100%) rename {linkedlist => algorithms/linkedlist}/reverse.py (100%) rename {linkedlist => algorithms/linkedlist}/rotate_list.py (100%) rename {linkedlist => algorithms/linkedlist}/swap_in_pairs.py (100%) delete mode 100644 linkedlist/__init__.py diff --git a/algorithms/linkedlist/__init__.py b/algorithms/linkedlist/__init__.py new file mode 100644 index 000000000..21263bfe9 --- /dev/null +++ b/algorithms/linkedlist/__init__.py @@ -0,0 +1,8 @@ +from .reverse import * +from .is_sorted import * +from .remove_range import * +from .swap_in_pairs import * +from .rotate_list import * +from .is_cyclic import * +from .merge_two_list import * +from .is_palindrome import * diff --git a/linkedlist/add_two_numbers.py b/algorithms/linkedlist/add_two_numbers.py similarity index 100% rename from linkedlist/add_two_numbers.py rename to algorithms/linkedlist/add_two_numbers.py diff --git a/linkedlist/copy_random_pointer.py b/algorithms/linkedlist/copy_random_pointer.py similarity index 100% rename from linkedlist/copy_random_pointer.py rename to algorithms/linkedlist/copy_random_pointer.py diff --git a/linkedlist/delete_node.py b/algorithms/linkedlist/delete_node.py similarity index 100% rename from linkedlist/delete_node.py rename to algorithms/linkedlist/delete_node.py diff --git a/linkedlist/first_cyclic_node.py b/algorithms/linkedlist/first_cyclic_node.py similarity index 100% rename from linkedlist/first_cyclic_node.py rename to algorithms/linkedlist/first_cyclic_node.py diff --git a/linkedlist/intersection.py b/algorithms/linkedlist/intersection.py similarity index 100% rename from linkedlist/intersection.py rename to algorithms/linkedlist/intersection.py diff --git a/linkedlist/is_cyclic.py b/algorithms/linkedlist/is_cyclic.py similarity index 100% rename from linkedlist/is_cyclic.py rename to algorithms/linkedlist/is_cyclic.py diff --git a/linkedlist/is_palindrome.py b/algorithms/linkedlist/is_palindrome.py similarity index 100% rename from linkedlist/is_palindrome.py rename to algorithms/linkedlist/is_palindrome.py diff --git a/linkedlist/is_sorted.py b/algorithms/linkedlist/is_sorted.py similarity index 100% rename from linkedlist/is_sorted.py rename to algorithms/linkedlist/is_sorted.py diff --git a/linkedlist/kth_to_last.py b/algorithms/linkedlist/kth_to_last.py similarity index 100% rename from linkedlist/kth_to_last.py rename to algorithms/linkedlist/kth_to_last.py diff --git a/linkedlist/linkedlist.py b/algorithms/linkedlist/linkedlist.py similarity index 100% rename from linkedlist/linkedlist.py rename to algorithms/linkedlist/linkedlist.py diff --git a/linkedlist/merge_two_list.py b/algorithms/linkedlist/merge_two_list.py similarity index 100% rename from linkedlist/merge_two_list.py rename to algorithms/linkedlist/merge_two_list.py diff --git a/linkedlist/partition.py b/algorithms/linkedlist/partition.py similarity index 100% rename from linkedlist/partition.py rename to algorithms/linkedlist/partition.py diff --git a/linkedlist/remove_duplicates.py b/algorithms/linkedlist/remove_duplicates.py similarity index 100% rename from linkedlist/remove_duplicates.py rename to algorithms/linkedlist/remove_duplicates.py diff --git a/linkedlist/remove_range.py b/algorithms/linkedlist/remove_range.py similarity index 100% rename from linkedlist/remove_range.py rename to algorithms/linkedlist/remove_range.py diff --git a/linkedlist/reverse.py b/algorithms/linkedlist/reverse.py similarity index 100% rename from linkedlist/reverse.py rename to algorithms/linkedlist/reverse.py diff --git a/linkedlist/rotate_list.py b/algorithms/linkedlist/rotate_list.py similarity index 100% rename from linkedlist/rotate_list.py rename to algorithms/linkedlist/rotate_list.py diff --git a/linkedlist/swap_in_pairs.py b/algorithms/linkedlist/swap_in_pairs.py similarity index 100% rename from linkedlist/swap_in_pairs.py rename to algorithms/linkedlist/swap_in_pairs.py diff --git a/linkedlist/__init__.py b/linkedlist/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_linkedlist.py b/tests/test_linkedlist.py index 89096bc9b..435ac7261 100644 --- a/tests/test_linkedlist.py +++ b/tests/test_linkedlist.py @@ -1,11 +1,13 @@ -from linkedlist.reverse import reverse_list, reverse_list_recursive -from linkedlist.is_sorted import is_sorted -from linkedlist.remove_range import remove_range -from linkedlist.swap_in_pairs import swap_pairs -from linkedlist.rotate_list import rotate_right -from linkedlist.is_cyclic import is_cyclic -from linkedlist.merge_two_list import merge_two_list, merge_two_list_recur -from linkedlist.is_palindrome import is_palindrome, is_palindrome_stack, is_palindrome_dict +from algorithms.linkedlist import ( + reverse_list, reverse_list_recursive, + is_sorted, + remove_range, + swap_pairs, + rotate_right, + is_cyclic, + merge_two_list, merge_two_list_recur, + is_palindrome, is_palindrome_stack, is_palindrome_dict +) import unittest From c9efa52ec15d46805116aa516143b35667c1f1a3 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:13:26 -0700 Subject: [PATCH 007/302] reorganize backtrack --- {backtrack => algorithms/backtrack}/anagram.py | 0 {backtrack => algorithms/backtrack}/array_sum_combinations.py | 0 {backtrack => algorithms/backtrack}/combination_sum.py | 0 {backtrack => algorithms/backtrack}/expression_add_operators.py | 0 {backtrack => algorithms/backtrack}/factor_combinations.py | 0 {backtrack => algorithms/backtrack}/general_solution.md | 0 {backtrack => algorithms/backtrack}/generate_abbreviations.py | 0 {backtrack => algorithms/backtrack}/generate_parenthesis.py | 0 {backtrack => algorithms/backtrack}/letter_combination.py | 0 {backtrack => algorithms/backtrack}/palindrome_partitioning.py | 0 {backtrack => algorithms/backtrack}/pattern_match.py | 0 {backtrack => algorithms/backtrack}/permute.py | 0 {backtrack => algorithms/backtrack}/permute_unique.py | 0 {backtrack => algorithms/backtrack}/subsets.py | 0 {backtrack => algorithms/backtrack}/subsets_unique.py | 0 {backtrack => algorithms/backtrack}/word_search.py | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename {backtrack => algorithms/backtrack}/anagram.py (100%) rename {backtrack => algorithms/backtrack}/array_sum_combinations.py (100%) rename {backtrack => algorithms/backtrack}/combination_sum.py (100%) rename {backtrack => algorithms/backtrack}/expression_add_operators.py (100%) rename {backtrack => algorithms/backtrack}/factor_combinations.py (100%) rename {backtrack => algorithms/backtrack}/general_solution.md (100%) rename {backtrack => algorithms/backtrack}/generate_abbreviations.py (100%) rename {backtrack => algorithms/backtrack}/generate_parenthesis.py (100%) rename {backtrack => algorithms/backtrack}/letter_combination.py (100%) rename {backtrack => algorithms/backtrack}/palindrome_partitioning.py (100%) rename {backtrack => algorithms/backtrack}/pattern_match.py (100%) rename {backtrack => algorithms/backtrack}/permute.py (100%) rename {backtrack => algorithms/backtrack}/permute_unique.py (100%) rename {backtrack => algorithms/backtrack}/subsets.py (100%) rename {backtrack => algorithms/backtrack}/subsets_unique.py (100%) rename {backtrack => algorithms/backtrack}/word_search.py (100%) diff --git a/backtrack/anagram.py b/algorithms/backtrack/anagram.py similarity index 100% rename from backtrack/anagram.py rename to algorithms/backtrack/anagram.py diff --git a/backtrack/array_sum_combinations.py b/algorithms/backtrack/array_sum_combinations.py similarity index 100% rename from backtrack/array_sum_combinations.py rename to algorithms/backtrack/array_sum_combinations.py diff --git a/backtrack/combination_sum.py b/algorithms/backtrack/combination_sum.py similarity index 100% rename from backtrack/combination_sum.py rename to algorithms/backtrack/combination_sum.py diff --git a/backtrack/expression_add_operators.py b/algorithms/backtrack/expression_add_operators.py similarity index 100% rename from backtrack/expression_add_operators.py rename to algorithms/backtrack/expression_add_operators.py diff --git a/backtrack/factor_combinations.py b/algorithms/backtrack/factor_combinations.py similarity index 100% rename from backtrack/factor_combinations.py rename to algorithms/backtrack/factor_combinations.py diff --git a/backtrack/general_solution.md b/algorithms/backtrack/general_solution.md similarity index 100% rename from backtrack/general_solution.md rename to algorithms/backtrack/general_solution.md diff --git a/backtrack/generate_abbreviations.py b/algorithms/backtrack/generate_abbreviations.py similarity index 100% rename from backtrack/generate_abbreviations.py rename to algorithms/backtrack/generate_abbreviations.py diff --git a/backtrack/generate_parenthesis.py b/algorithms/backtrack/generate_parenthesis.py similarity index 100% rename from backtrack/generate_parenthesis.py rename to algorithms/backtrack/generate_parenthesis.py diff --git a/backtrack/letter_combination.py b/algorithms/backtrack/letter_combination.py similarity index 100% rename from backtrack/letter_combination.py rename to algorithms/backtrack/letter_combination.py diff --git a/backtrack/palindrome_partitioning.py b/algorithms/backtrack/palindrome_partitioning.py similarity index 100% rename from backtrack/palindrome_partitioning.py rename to algorithms/backtrack/palindrome_partitioning.py diff --git a/backtrack/pattern_match.py b/algorithms/backtrack/pattern_match.py similarity index 100% rename from backtrack/pattern_match.py rename to algorithms/backtrack/pattern_match.py diff --git a/backtrack/permute.py b/algorithms/backtrack/permute.py similarity index 100% rename from backtrack/permute.py rename to algorithms/backtrack/permute.py diff --git a/backtrack/permute_unique.py b/algorithms/backtrack/permute_unique.py similarity index 100% rename from backtrack/permute_unique.py rename to algorithms/backtrack/permute_unique.py diff --git a/backtrack/subsets.py b/algorithms/backtrack/subsets.py similarity index 100% rename from backtrack/subsets.py rename to algorithms/backtrack/subsets.py diff --git a/backtrack/subsets_unique.py b/algorithms/backtrack/subsets_unique.py similarity index 100% rename from backtrack/subsets_unique.py rename to algorithms/backtrack/subsets_unique.py diff --git a/backtrack/word_search.py b/algorithms/backtrack/word_search.py similarity index 100% rename from backtrack/word_search.py rename to algorithms/backtrack/word_search.py From 567c619b905f765039efddebcc897e38a423cf35 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:16:08 -0700 Subject: [PATCH 008/302] reorganize bfs --- {bfs => algorithms/bfs}/shortest_distance_from_all_buildings.py | 0 {bfs => algorithms/bfs}/word_ladder.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {bfs => algorithms/bfs}/shortest_distance_from_all_buildings.py (100%) rename {bfs => algorithms/bfs}/word_ladder.py (100%) diff --git a/bfs/shortest_distance_from_all_buildings.py b/algorithms/bfs/shortest_distance_from_all_buildings.py similarity index 100% rename from bfs/shortest_distance_from_all_buildings.py rename to algorithms/bfs/shortest_distance_from_all_buildings.py diff --git a/bfs/word_ladder.py b/algorithms/bfs/word_ladder.py similarity index 100% rename from bfs/word_ladder.py rename to algorithms/bfs/word_ladder.py From 1a25a844905b74fd236d3018c6d9fb595b880908 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:17:31 -0700 Subject: [PATCH 009/302] reorganize dfs --- {dfs => algorithms/dfs}/all_factors.py | 0 {dfs => algorithms/dfs}/count_islands.py | 0 {dfs => algorithms/dfs}/pacific_atlantic.py | 0 {dfs => algorithms/dfs}/sudoku_solver.py | 0 {dfs => algorithms/dfs}/walls_and_gates.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename {dfs => algorithms/dfs}/all_factors.py (100%) rename {dfs => algorithms/dfs}/count_islands.py (100%) rename {dfs => algorithms/dfs}/pacific_atlantic.py (100%) rename {dfs => algorithms/dfs}/sudoku_solver.py (100%) rename {dfs => algorithms/dfs}/walls_and_gates.py (100%) diff --git a/dfs/all_factors.py b/algorithms/dfs/all_factors.py similarity index 100% rename from dfs/all_factors.py rename to algorithms/dfs/all_factors.py diff --git a/dfs/count_islands.py b/algorithms/dfs/count_islands.py similarity index 100% rename from dfs/count_islands.py rename to algorithms/dfs/count_islands.py diff --git a/dfs/pacific_atlantic.py b/algorithms/dfs/pacific_atlantic.py similarity index 100% rename from dfs/pacific_atlantic.py rename to algorithms/dfs/pacific_atlantic.py diff --git a/dfs/sudoku_solver.py b/algorithms/dfs/sudoku_solver.py similarity index 100% rename from dfs/sudoku_solver.py rename to algorithms/dfs/sudoku_solver.py diff --git a/dfs/walls_and_gates.py b/algorithms/dfs/walls_and_gates.py similarity index 100% rename from dfs/walls_and_gates.py rename to algorithms/dfs/walls_and_gates.py From 3c4325afe6d5c1c126c7dd224f2ac827ec581e3c Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:19:51 -0700 Subject: [PATCH 010/302] reorganize dp --- {dp => algorithms/dp}/buy_sell_stock.py | 0 {dp => algorithms/dp}/climbing_stairs.py | 0 {dp => algorithms/dp}/coin_change.py | 0 {dp => algorithms/dp}/combination_sum.py | 0 {dp => algorithms/dp}/egg_drop.py | 0 {dp => algorithms/dp}/fib.py | 0 {dp => algorithms/dp}/house_robber.py | 0 {dp => algorithms/dp}/job_scheduling.py | 0 {dp => algorithms/dp}/knapsack.py | 0 {dp => algorithms/dp}/longest_increasing.py | 0 {dp => algorithms/dp}/matrix_chain_order.py | 0 {dp => algorithms/dp}/max_product_subarray.py | 0 {dp => algorithms/dp}/max_subarray.py | 0 {dp => algorithms/dp}/min_cost_path.py | 0 {dp => algorithms/dp}/num_decodings.py | 0 {dp => algorithms/dp}/regex_matching.py | 0 {dp => algorithms/dp}/rod_cut.py | 0 {dp => algorithms/dp}/word_break.py | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename {dp => algorithms/dp}/buy_sell_stock.py (100%) rename {dp => algorithms/dp}/climbing_stairs.py (100%) rename {dp => algorithms/dp}/coin_change.py (100%) rename {dp => algorithms/dp}/combination_sum.py (100%) rename {dp => algorithms/dp}/egg_drop.py (100%) rename {dp => algorithms/dp}/fib.py (100%) rename {dp => algorithms/dp}/house_robber.py (100%) rename {dp => algorithms/dp}/job_scheduling.py (100%) rename {dp => algorithms/dp}/knapsack.py (100%) rename {dp => algorithms/dp}/longest_increasing.py (100%) rename {dp => algorithms/dp}/matrix_chain_order.py (100%) rename {dp => algorithms/dp}/max_product_subarray.py (100%) rename {dp => algorithms/dp}/max_subarray.py (100%) rename {dp => algorithms/dp}/min_cost_path.py (100%) rename {dp => algorithms/dp}/num_decodings.py (100%) rename {dp => algorithms/dp}/regex_matching.py (100%) rename {dp => algorithms/dp}/rod_cut.py (100%) rename {dp => algorithms/dp}/word_break.py (100%) diff --git a/dp/buy_sell_stock.py b/algorithms/dp/buy_sell_stock.py similarity index 100% rename from dp/buy_sell_stock.py rename to algorithms/dp/buy_sell_stock.py diff --git a/dp/climbing_stairs.py b/algorithms/dp/climbing_stairs.py similarity index 100% rename from dp/climbing_stairs.py rename to algorithms/dp/climbing_stairs.py diff --git a/dp/coin_change.py b/algorithms/dp/coin_change.py similarity index 100% rename from dp/coin_change.py rename to algorithms/dp/coin_change.py diff --git a/dp/combination_sum.py b/algorithms/dp/combination_sum.py similarity index 100% rename from dp/combination_sum.py rename to algorithms/dp/combination_sum.py diff --git a/dp/egg_drop.py b/algorithms/dp/egg_drop.py similarity index 100% rename from dp/egg_drop.py rename to algorithms/dp/egg_drop.py diff --git a/dp/fib.py b/algorithms/dp/fib.py similarity index 100% rename from dp/fib.py rename to algorithms/dp/fib.py diff --git a/dp/house_robber.py b/algorithms/dp/house_robber.py similarity index 100% rename from dp/house_robber.py rename to algorithms/dp/house_robber.py diff --git a/dp/job_scheduling.py b/algorithms/dp/job_scheduling.py similarity index 100% rename from dp/job_scheduling.py rename to algorithms/dp/job_scheduling.py diff --git a/dp/knapsack.py b/algorithms/dp/knapsack.py similarity index 100% rename from dp/knapsack.py rename to algorithms/dp/knapsack.py diff --git a/dp/longest_increasing.py b/algorithms/dp/longest_increasing.py similarity index 100% rename from dp/longest_increasing.py rename to algorithms/dp/longest_increasing.py diff --git a/dp/matrix_chain_order.py b/algorithms/dp/matrix_chain_order.py similarity index 100% rename from dp/matrix_chain_order.py rename to algorithms/dp/matrix_chain_order.py diff --git a/dp/max_product_subarray.py b/algorithms/dp/max_product_subarray.py similarity index 100% rename from dp/max_product_subarray.py rename to algorithms/dp/max_product_subarray.py diff --git a/dp/max_subarray.py b/algorithms/dp/max_subarray.py similarity index 100% rename from dp/max_subarray.py rename to algorithms/dp/max_subarray.py diff --git a/dp/min_cost_path.py b/algorithms/dp/min_cost_path.py similarity index 100% rename from dp/min_cost_path.py rename to algorithms/dp/min_cost_path.py diff --git a/dp/num_decodings.py b/algorithms/dp/num_decodings.py similarity index 100% rename from dp/num_decodings.py rename to algorithms/dp/num_decodings.py diff --git a/dp/regex_matching.py b/algorithms/dp/regex_matching.py similarity index 100% rename from dp/regex_matching.py rename to algorithms/dp/regex_matching.py diff --git a/dp/rod_cut.py b/algorithms/dp/rod_cut.py similarity index 100% rename from dp/rod_cut.py rename to algorithms/dp/rod_cut.py diff --git a/dp/word_break.py b/algorithms/dp/word_break.py similarity index 100% rename from dp/word_break.py rename to algorithms/dp/word_break.py From f84a0d4c21c702adf6ff1363cee8ba0a70ef4081 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:28:37 -0700 Subject: [PATCH 011/302] reorganize graph --- {graph => algorithms/graph}/Transitive_Closure_DFS.py | 0 algorithms/graph/__init__.py | 1 + {graph => algorithms/graph}/checkDiGraphStronglyConnected.py | 0 {graph => algorithms/graph}/clone_graph.py | 0 {graph => algorithms/graph}/cycle_detection.py | 0 {graph => algorithms/graph}/dijkstra.py | 0 {graph => algorithms/graph}/find_all_cliques.py | 0 {graph => algorithms/graph}/find_path.py | 0 {graph => algorithms/graph}/graph.py | 0 {graph => algorithms/graph}/markov_chain.py | 0 {graph => algorithms/graph}/minimum_spanning_tree.py | 0 .../graph}/pathBetweenTwoVerticesInDiGraph.py | 0 {graph => algorithms/graph}/satisfiability.py | 0 {graph => algorithms/graph}/tarjan.py | 4 ++-- {graph => algorithms/graph}/traversal.py | 0 graph/__init__.py | 0 tests/test_graph.py | 4 ++-- 17 files changed, 5 insertions(+), 4 deletions(-) rename {graph => algorithms/graph}/Transitive_Closure_DFS.py (100%) create mode 100644 algorithms/graph/__init__.py rename {graph => algorithms/graph}/checkDiGraphStronglyConnected.py (100%) rename {graph => algorithms/graph}/clone_graph.py (100%) rename {graph => algorithms/graph}/cycle_detection.py (100%) rename {graph => algorithms/graph}/dijkstra.py (100%) rename {graph => algorithms/graph}/find_all_cliques.py (100%) rename {graph => algorithms/graph}/find_path.py (100%) rename {graph => algorithms/graph}/graph.py (100%) rename {graph => algorithms/graph}/markov_chain.py (100%) rename {graph => algorithms/graph}/minimum_spanning_tree.py (100%) rename {graph => algorithms/graph}/pathBetweenTwoVerticesInDiGraph.py (100%) rename {graph => algorithms/graph}/satisfiability.py (100%) rename {graph => algorithms/graph}/tarjan.py (97%) rename {graph => algorithms/graph}/traversal.py (100%) delete mode 100644 graph/__init__.py diff --git a/graph/Transitive_Closure_DFS.py b/algorithms/graph/Transitive_Closure_DFS.py similarity index 100% rename from graph/Transitive_Closure_DFS.py rename to algorithms/graph/Transitive_Closure_DFS.py diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py new file mode 100644 index 000000000..bfb208eb0 --- /dev/null +++ b/algorithms/graph/__init__.py @@ -0,0 +1 @@ +from .tarjan import * diff --git a/graph/checkDiGraphStronglyConnected.py b/algorithms/graph/checkDiGraphStronglyConnected.py similarity index 100% rename from graph/checkDiGraphStronglyConnected.py rename to algorithms/graph/checkDiGraphStronglyConnected.py diff --git a/graph/clone_graph.py b/algorithms/graph/clone_graph.py similarity index 100% rename from graph/clone_graph.py rename to algorithms/graph/clone_graph.py diff --git a/graph/cycle_detection.py b/algorithms/graph/cycle_detection.py similarity index 100% rename from graph/cycle_detection.py rename to algorithms/graph/cycle_detection.py diff --git a/graph/dijkstra.py b/algorithms/graph/dijkstra.py similarity index 100% rename from graph/dijkstra.py rename to algorithms/graph/dijkstra.py diff --git a/graph/find_all_cliques.py b/algorithms/graph/find_all_cliques.py similarity index 100% rename from graph/find_all_cliques.py rename to algorithms/graph/find_all_cliques.py diff --git a/graph/find_path.py b/algorithms/graph/find_path.py similarity index 100% rename from graph/find_path.py rename to algorithms/graph/find_path.py diff --git a/graph/graph.py b/algorithms/graph/graph.py similarity index 100% rename from graph/graph.py rename to algorithms/graph/graph.py diff --git a/graph/markov_chain.py b/algorithms/graph/markov_chain.py similarity index 100% rename from graph/markov_chain.py rename to algorithms/graph/markov_chain.py diff --git a/graph/minimum_spanning_tree.py b/algorithms/graph/minimum_spanning_tree.py similarity index 100% rename from graph/minimum_spanning_tree.py rename to algorithms/graph/minimum_spanning_tree.py diff --git a/graph/pathBetweenTwoVerticesInDiGraph.py b/algorithms/graph/pathBetweenTwoVerticesInDiGraph.py similarity index 100% rename from graph/pathBetweenTwoVerticesInDiGraph.py rename to algorithms/graph/pathBetweenTwoVerticesInDiGraph.py diff --git a/graph/satisfiability.py b/algorithms/graph/satisfiability.py similarity index 100% rename from graph/satisfiability.py rename to algorithms/graph/satisfiability.py diff --git a/graph/tarjan.py b/algorithms/graph/tarjan.py similarity index 97% rename from graph/tarjan.py rename to algorithms/graph/tarjan.py index 584999b49..a2f44e58d 100644 --- a/graph/tarjan.py +++ b/algorithms/graph/tarjan.py @@ -3,7 +3,7 @@ in a graph. https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm """ -from graph.graph import DirectedGraph +from algorithms.graph.graph import DirectedGraph class Tarjan(object): def __init__(self, dict_graph): @@ -54,4 +54,4 @@ def strongconnect(self, v, sccs): break scc.sort() sccs.append(scc) - \ No newline at end of file + diff --git a/graph/traversal.py b/algorithms/graph/traversal.py similarity index 100% rename from graph/traversal.py rename to algorithms/graph/traversal.py diff --git a/graph/__init__.py b/graph/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_graph.py b/tests/test_graph.py index e62a10226..63937db0e 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,4 +1,4 @@ -from graph.tarjan import Tarjan +from algorithms.graph import Tarjan import unittest @@ -41,4 +41,4 @@ def test_tarjan_example_2(self): } g = Tarjan(example) - self.assertEqual(g.sccs, [['A', 'B', 'E'], ['C', 'D'], ['F', 'G'], ['H']]) \ No newline at end of file + self.assertEqual(g.sccs, [['A', 'B', 'E'], ['C', 'D'], ['F', 'G'], ['H']]) From 7760d36639bb22a54d7913c3b49f01d744b44c6d Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:34:49 -0700 Subject: [PATCH 012/302] reorganize heap --- algorithms/heap/__init__.py | 3 +++ {heap => algorithms/heap}/binary_heap.py | 0 {heap => algorithms/heap}/merge_sorted_k_lists.py | 0 {heap => algorithms/heap}/skyline.py | 0 {heap => algorithms/heap}/sliding_window_max.py | 0 heap/__init__.py | 0 tests/test_heap.py | 8 +++++--- 7 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 algorithms/heap/__init__.py rename {heap => algorithms/heap}/binary_heap.py (100%) rename {heap => algorithms/heap}/merge_sorted_k_lists.py (100%) rename {heap => algorithms/heap}/skyline.py (100%) rename {heap => algorithms/heap}/sliding_window_max.py (100%) delete mode 100644 heap/__init__.py diff --git a/algorithms/heap/__init__.py b/algorithms/heap/__init__.py new file mode 100644 index 000000000..3731b0ee9 --- /dev/null +++ b/algorithms/heap/__init__.py @@ -0,0 +1,3 @@ +from .binary_heap import * +from .skyline import * +from .sliding_window_max import * diff --git a/heap/binary_heap.py b/algorithms/heap/binary_heap.py similarity index 100% rename from heap/binary_heap.py rename to algorithms/heap/binary_heap.py diff --git a/heap/merge_sorted_k_lists.py b/algorithms/heap/merge_sorted_k_lists.py similarity index 100% rename from heap/merge_sorted_k_lists.py rename to algorithms/heap/merge_sorted_k_lists.py diff --git a/heap/skyline.py b/algorithms/heap/skyline.py similarity index 100% rename from heap/skyline.py rename to algorithms/heap/skyline.py diff --git a/heap/sliding_window_max.py b/algorithms/heap/sliding_window_max.py similarity index 100% rename from heap/sliding_window_max.py rename to algorithms/heap/sliding_window_max.py diff --git a/heap/__init__.py b/heap/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_heap.py b/tests/test_heap.py index c6f2c7e60..0925972dd 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -1,6 +1,8 @@ -from heap.binary_heap import BinaryHeap -from heap.skyline import get_skyline -from heap.sliding_window_max import max_sliding_window +from algorithms.heap import ( + BinaryHeap, + get_skyline, + max_sliding_window +) import unittest From feceb6c4912f36900cefb2da15e6bc6c3e31b4a4 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:36:17 -0700 Subject: [PATCH 013/302] reorganize map --- {map => algorithms/map}/hashtable.py | 0 {map => algorithms/map}/longest_common_subsequence.py | 0 {map => algorithms/map}/randomized_set.py | 0 {map => algorithms/map}/separate_chaining_hashtable.py | 0 {map => algorithms/map}/valid_sudoku.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename {map => algorithms/map}/hashtable.py (100%) rename {map => algorithms/map}/longest_common_subsequence.py (100%) rename {map => algorithms/map}/randomized_set.py (100%) rename {map => algorithms/map}/separate_chaining_hashtable.py (100%) rename {map => algorithms/map}/valid_sudoku.py (100%) diff --git a/map/hashtable.py b/algorithms/map/hashtable.py similarity index 100% rename from map/hashtable.py rename to algorithms/map/hashtable.py diff --git a/map/longest_common_subsequence.py b/algorithms/map/longest_common_subsequence.py similarity index 100% rename from map/longest_common_subsequence.py rename to algorithms/map/longest_common_subsequence.py diff --git a/map/randomized_set.py b/algorithms/map/randomized_set.py similarity index 100% rename from map/randomized_set.py rename to algorithms/map/randomized_set.py diff --git a/map/separate_chaining_hashtable.py b/algorithms/map/separate_chaining_hashtable.py similarity index 100% rename from map/separate_chaining_hashtable.py rename to algorithms/map/separate_chaining_hashtable.py diff --git a/map/valid_sudoku.py b/algorithms/map/valid_sudoku.py similarity index 100% rename from map/valid_sudoku.py rename to algorithms/map/valid_sudoku.py From f9bb8a072f1b31310a8ab60d657abc491c00c523 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:40:58 -0700 Subject: [PATCH 014/302] reorganize maths --- algorithms/maths/__init__.py | 11 +++++++++ .../maths}/base_conversion.py | 0 {maths => algorithms/maths}/extended_gcd.py | 0 {maths => algorithms/maths}/gcd.py | 0 .../maths}/generate_strobogrammtic.py | 0 .../maths}/is_strobogrammatic.py | 0 {maths => algorithms/maths}/next_bigger.py | 0 .../maths}/next_perfect_square.py | 0 {maths => algorithms/maths}/nth_digit.py | 0 {maths => algorithms/maths}/prime_check.py | 0 .../maths}/primes_sieve_of_eratosthenes.py | 0 {maths => algorithms/maths}/pythagoras.py | 0 {maths => algorithms/maths}/rabin_miller.py | 0 {maths => algorithms/maths}/rsa.py | 0 .../maths}/sqrt_precision_factor.py | 0 {maths => algorithms/maths}/summing_digits.py | 0 maths/__init__.py | 0 tests/test_maths.py | 24 ++++++++++--------- 18 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 algorithms/maths/__init__.py rename {maths => algorithms/maths}/base_conversion.py (100%) rename {maths => algorithms/maths}/extended_gcd.py (100%) rename {maths => algorithms/maths}/gcd.py (100%) rename {maths => algorithms/maths}/generate_strobogrammtic.py (100%) rename {maths => algorithms/maths}/is_strobogrammatic.py (100%) rename {maths => algorithms/maths}/next_bigger.py (100%) rename {maths => algorithms/maths}/next_perfect_square.py (100%) rename {maths => algorithms/maths}/nth_digit.py (100%) rename {maths => algorithms/maths}/prime_check.py (100%) rename {maths => algorithms/maths}/primes_sieve_of_eratosthenes.py (100%) rename {maths => algorithms/maths}/pythagoras.py (100%) rename {maths => algorithms/maths}/rabin_miller.py (100%) rename {maths => algorithms/maths}/rsa.py (100%) rename {maths => algorithms/maths}/sqrt_precision_factor.py (100%) rename {maths => algorithms/maths}/summing_digits.py (100%) delete mode 100644 maths/__init__.py diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py new file mode 100644 index 000000000..6716384ba --- /dev/null +++ b/algorithms/maths/__init__.py @@ -0,0 +1,11 @@ +from .base_conversion import * +from .extended_gcd import * +from .gcd import * +from .generate_strobogrammtic import * +from .is_strobogrammatic import * +from .next_perfect_square import * +from .prime_check import * +from .primes_sieve_of_eratosthenes import * +from .pythagoras import * +from .rabin_miller import * +from .rsa import * diff --git a/maths/base_conversion.py b/algorithms/maths/base_conversion.py similarity index 100% rename from maths/base_conversion.py rename to algorithms/maths/base_conversion.py diff --git a/maths/extended_gcd.py b/algorithms/maths/extended_gcd.py similarity index 100% rename from maths/extended_gcd.py rename to algorithms/maths/extended_gcd.py diff --git a/maths/gcd.py b/algorithms/maths/gcd.py similarity index 100% rename from maths/gcd.py rename to algorithms/maths/gcd.py diff --git a/maths/generate_strobogrammtic.py b/algorithms/maths/generate_strobogrammtic.py similarity index 100% rename from maths/generate_strobogrammtic.py rename to algorithms/maths/generate_strobogrammtic.py diff --git a/maths/is_strobogrammatic.py b/algorithms/maths/is_strobogrammatic.py similarity index 100% rename from maths/is_strobogrammatic.py rename to algorithms/maths/is_strobogrammatic.py diff --git a/maths/next_bigger.py b/algorithms/maths/next_bigger.py similarity index 100% rename from maths/next_bigger.py rename to algorithms/maths/next_bigger.py diff --git a/maths/next_perfect_square.py b/algorithms/maths/next_perfect_square.py similarity index 100% rename from maths/next_perfect_square.py rename to algorithms/maths/next_perfect_square.py diff --git a/maths/nth_digit.py b/algorithms/maths/nth_digit.py similarity index 100% rename from maths/nth_digit.py rename to algorithms/maths/nth_digit.py diff --git a/maths/prime_check.py b/algorithms/maths/prime_check.py similarity index 100% rename from maths/prime_check.py rename to algorithms/maths/prime_check.py diff --git a/maths/primes_sieve_of_eratosthenes.py b/algorithms/maths/primes_sieve_of_eratosthenes.py similarity index 100% rename from maths/primes_sieve_of_eratosthenes.py rename to algorithms/maths/primes_sieve_of_eratosthenes.py diff --git a/maths/pythagoras.py b/algorithms/maths/pythagoras.py similarity index 100% rename from maths/pythagoras.py rename to algorithms/maths/pythagoras.py diff --git a/maths/rabin_miller.py b/algorithms/maths/rabin_miller.py similarity index 100% rename from maths/rabin_miller.py rename to algorithms/maths/rabin_miller.py diff --git a/maths/rsa.py b/algorithms/maths/rsa.py similarity index 100% rename from maths/rsa.py rename to algorithms/maths/rsa.py diff --git a/maths/sqrt_precision_factor.py b/algorithms/maths/sqrt_precision_factor.py similarity index 100% rename from maths/sqrt_precision_factor.py rename to algorithms/maths/sqrt_precision_factor.py diff --git a/maths/summing_digits.py b/algorithms/maths/summing_digits.py similarity index 100% rename from maths/summing_digits.py rename to algorithms/maths/summing_digits.py diff --git a/maths/__init__.py b/maths/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_maths.py b/tests/test_maths.py index a7567f72f..afafd2ec5 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,14 +1,16 @@ -from maths.base_conversion import int2base, base2int -from maths.extended_gcd import extended_gcd -from maths.gcd import gcd, lcm -from maths.generate_strobogrammtic import gen_strobogrammatic, strobogrammatic_in_range -from maths.is_strobogrammatic import is_strobogrammatic, is_strobogrammatic2 -from maths.next_perfect_square import find_next_square, find_next_square2 -from maths.prime_check import prime_check, prime_check2 -from maths.primes_sieve_of_eratosthenes import primes -from maths.pythagoras import pythagoras -from maths.rabin_miller import is_prime -from maths.rsa import encrypt, decrypt, generate_key +from algorithms.maths import ( + int2base, base2int, + extended_gcd, + gcd, lcm, + gen_strobogrammatic, strobogrammatic_in_range, + is_strobogrammatic, is_strobogrammatic2, + find_next_square, find_next_square2, + prime_check, prime_check2, + primes, + pythagoras, + is_prime, + encrypt, decrypt, generate_key +) import unittest From c611fdadefa458b149fd1e6b48bd78899c5a41d5 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:42:03 -0700 Subject: [PATCH 015/302] reorganize matrix --- {matrix => algorithms/matrix}/bomb_enemy.py | 0 {matrix => algorithms/matrix}/copy_transform.py | 0 {matrix => algorithms/matrix}/count_paths.py | 0 {matrix => algorithms/matrix}/matrix_rotation.txt | 0 {matrix => algorithms/matrix}/rotate_image.py | 0 {matrix => algorithms/matrix}/search_in_sorted_matrix.py | 0 {matrix => algorithms/matrix}/sparse_dot_vector.py | 0 {matrix => algorithms/matrix}/sparse_mul.py | 0 {matrix => algorithms/matrix}/spiral_traversal.py | 0 {matrix => algorithms/matrix}/sudoku_validator.py | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {matrix => algorithms/matrix}/bomb_enemy.py (100%) rename {matrix => algorithms/matrix}/copy_transform.py (100%) rename {matrix => algorithms/matrix}/count_paths.py (100%) rename {matrix => algorithms/matrix}/matrix_rotation.txt (100%) rename {matrix => algorithms/matrix}/rotate_image.py (100%) rename {matrix => algorithms/matrix}/search_in_sorted_matrix.py (100%) rename {matrix => algorithms/matrix}/sparse_dot_vector.py (100%) rename {matrix => algorithms/matrix}/sparse_mul.py (100%) rename {matrix => algorithms/matrix}/spiral_traversal.py (100%) rename {matrix => algorithms/matrix}/sudoku_validator.py (100%) diff --git a/matrix/bomb_enemy.py b/algorithms/matrix/bomb_enemy.py similarity index 100% rename from matrix/bomb_enemy.py rename to algorithms/matrix/bomb_enemy.py diff --git a/matrix/copy_transform.py b/algorithms/matrix/copy_transform.py similarity index 100% rename from matrix/copy_transform.py rename to algorithms/matrix/copy_transform.py diff --git a/matrix/count_paths.py b/algorithms/matrix/count_paths.py similarity index 100% rename from matrix/count_paths.py rename to algorithms/matrix/count_paths.py diff --git a/matrix/matrix_rotation.txt b/algorithms/matrix/matrix_rotation.txt similarity index 100% rename from matrix/matrix_rotation.txt rename to algorithms/matrix/matrix_rotation.txt diff --git a/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py similarity index 100% rename from matrix/rotate_image.py rename to algorithms/matrix/rotate_image.py diff --git a/matrix/search_in_sorted_matrix.py b/algorithms/matrix/search_in_sorted_matrix.py similarity index 100% rename from matrix/search_in_sorted_matrix.py rename to algorithms/matrix/search_in_sorted_matrix.py diff --git a/matrix/sparse_dot_vector.py b/algorithms/matrix/sparse_dot_vector.py similarity index 100% rename from matrix/sparse_dot_vector.py rename to algorithms/matrix/sparse_dot_vector.py diff --git a/matrix/sparse_mul.py b/algorithms/matrix/sparse_mul.py similarity index 100% rename from matrix/sparse_mul.py rename to algorithms/matrix/sparse_mul.py diff --git a/matrix/spiral_traversal.py b/algorithms/matrix/spiral_traversal.py similarity index 100% rename from matrix/spiral_traversal.py rename to algorithms/matrix/spiral_traversal.py diff --git a/matrix/sudoku_validator.py b/algorithms/matrix/sudoku_validator.py similarity index 100% rename from matrix/sudoku_validator.py rename to algorithms/matrix/sudoku_validator.py From 000d6b3241028af48e199867c1cbc528578cd6a5 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:46:00 -0700 Subject: [PATCH 016/302] reorganize queue --- algorithms/queues/__init__.py | 4 ++++ {queues => algorithms/queues}/max_sliding_window.py | 0 {queues => algorithms/queues}/moving_average.py | 0 {queues => algorithms/queues}/priority_queue.py | 0 {queues => algorithms/queues}/queue.py | 0 {queues => algorithms/queues}/reconstruct_queue.py | 0 {queues => algorithms/queues}/zigzagiterator.py | 0 queues/__init__.py | 1 - tests/test_queues.py | 11 +++++++---- 9 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 algorithms/queues/__init__.py rename {queues => algorithms/queues}/max_sliding_window.py (100%) rename {queues => algorithms/queues}/moving_average.py (100%) rename {queues => algorithms/queues}/priority_queue.py (100%) rename {queues => algorithms/queues}/queue.py (100%) rename {queues => algorithms/queues}/reconstruct_queue.py (100%) rename {queues => algorithms/queues}/zigzagiterator.py (100%) delete mode 100644 queues/__init__.py diff --git a/algorithms/queues/__init__.py b/algorithms/queues/__init__.py new file mode 100644 index 000000000..3c4f22ca0 --- /dev/null +++ b/algorithms/queues/__init__.py @@ -0,0 +1,4 @@ +from .queue import * +from .max_sliding_window import * +from .reconstruct_queue import * +from .priority_queue import * diff --git a/queues/max_sliding_window.py b/algorithms/queues/max_sliding_window.py similarity index 100% rename from queues/max_sliding_window.py rename to algorithms/queues/max_sliding_window.py diff --git a/queues/moving_average.py b/algorithms/queues/moving_average.py similarity index 100% rename from queues/moving_average.py rename to algorithms/queues/moving_average.py diff --git a/queues/priority_queue.py b/algorithms/queues/priority_queue.py similarity index 100% rename from queues/priority_queue.py rename to algorithms/queues/priority_queue.py diff --git a/queues/queue.py b/algorithms/queues/queue.py similarity index 100% rename from queues/queue.py rename to algorithms/queues/queue.py diff --git a/queues/reconstruct_queue.py b/algorithms/queues/reconstruct_queue.py similarity index 100% rename from queues/reconstruct_queue.py rename to algorithms/queues/reconstruct_queue.py diff --git a/queues/zigzagiterator.py b/algorithms/queues/zigzagiterator.py similarity index 100% rename from queues/zigzagiterator.py rename to algorithms/queues/zigzagiterator.py diff --git a/queues/__init__.py b/queues/__init__.py deleted file mode 100644 index 2b5cb8ad8..000000000 --- a/queues/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .queue import * diff --git a/tests/test_queues.py b/tests/test_queues.py index a37d95f43..e5a882abd 100644 --- a/tests/test_queues.py +++ b/tests/test_queues.py @@ -1,7 +1,10 @@ -from queues.queue import ArrayQueue, LinkedListQueue -from queues.max_sliding_window import max_sliding_window -from queues.reconstruct_queue import reconstruct_queue -from queues.priority_queue import PriorityQueue, PriorityQueueNode +from algorithms.queues import ( + ArrayQueue, LinkedListQueue, + max_sliding_window, + reconstruct_queue, + PriorityQueue, PriorityQueueNode +) + import unittest class TestQueue(unittest.TestCase): From d71bfe14ef13224f6a2659570555e16b47a40e60 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:50:30 -0700 Subject: [PATCH 017/302] reorganize search --- algorithms/search/__init__.py | 8 ++++++++ {search => algorithms/search}/binary_search.py | 0 .../search}/find_min_rotate.py | 0 .../search}/first_occurance.py | 0 .../search}/last_occurance.py | 0 {search => algorithms/search}/search_insert.py | 0 {search => algorithms/search}/search_range.py | 0 {search => algorithms/search}/search_rotate.py | 0 {search => algorithms/search}/two_sum.py | 0 search/__init__.py | 0 tests/test_search.py | 18 ++++++++++-------- 11 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 algorithms/search/__init__.py rename {search => algorithms/search}/binary_search.py (100%) rename {search => algorithms/search}/find_min_rotate.py (100%) rename {search => algorithms/search}/first_occurance.py (100%) rename {search => algorithms/search}/last_occurance.py (100%) rename {search => algorithms/search}/search_insert.py (100%) rename {search => algorithms/search}/search_range.py (100%) rename {search => algorithms/search}/search_rotate.py (100%) rename {search => algorithms/search}/two_sum.py (100%) delete mode 100644 search/__init__.py diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py new file mode 100644 index 000000000..cebea34fd --- /dev/null +++ b/algorithms/search/__init__.py @@ -0,0 +1,8 @@ +from .binary_search import * +from .first_occurance import * +from .last_occurance import * +from .search_insert import * +from .two_sum import * +from .search_range import * +from .find_min_rotate import * +from .search_rotate import * diff --git a/search/binary_search.py b/algorithms/search/binary_search.py similarity index 100% rename from search/binary_search.py rename to algorithms/search/binary_search.py diff --git a/search/find_min_rotate.py b/algorithms/search/find_min_rotate.py similarity index 100% rename from search/find_min_rotate.py rename to algorithms/search/find_min_rotate.py diff --git a/search/first_occurance.py b/algorithms/search/first_occurance.py similarity index 100% rename from search/first_occurance.py rename to algorithms/search/first_occurance.py diff --git a/search/last_occurance.py b/algorithms/search/last_occurance.py similarity index 100% rename from search/last_occurance.py rename to algorithms/search/last_occurance.py diff --git a/search/search_insert.py b/algorithms/search/search_insert.py similarity index 100% rename from search/search_insert.py rename to algorithms/search/search_insert.py diff --git a/search/search_range.py b/algorithms/search/search_range.py similarity index 100% rename from search/search_range.py rename to algorithms/search/search_range.py diff --git a/search/search_rotate.py b/algorithms/search/search_rotate.py similarity index 100% rename from search/search_rotate.py rename to algorithms/search/search_rotate.py diff --git a/search/two_sum.py b/algorithms/search/two_sum.py similarity index 100% rename from search/two_sum.py rename to algorithms/search/two_sum.py diff --git a/search/__init__.py b/search/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_search.py b/tests/test_search.py index ca55940fd..4567ec559 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -1,11 +1,13 @@ -from search.binary_search import binary_search, binary_search_recur -from search.first_occurance import first_occurance -from search.last_occurance import last_occurance -from search.search_insert import search_insert -from search.two_sum import two_sum, two_sum1, two_sum2 -from search.search_range import search_range -from search.find_min_rotate import find_min_rotate, find_min_rotate_recur -from search.search_rotate import search_rotate, search_rotate_recur +from algorithms.search import ( + binary_search, binary_search_recur, + first_occurance, + last_occurance, + search_insert, + two_sum, two_sum1, two_sum2, + search_range, + find_min_rotate, find_min_rotate_recur, + search_rotate, search_rotate_recur +) import unittest From c343b7a70957e9dcbdc51e7f514e1eedde1ff356 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:51:40 -0700 Subject: [PATCH 018/302] reorganize set --- {set => algorithms/set}/randomized_set.py | 0 {set => algorithms/set}/set_covering.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {set => algorithms/set}/randomized_set.py (100%) rename {set => algorithms/set}/set_covering.py (100%) diff --git a/set/randomized_set.py b/algorithms/set/randomized_set.py similarity index 100% rename from set/randomized_set.py rename to algorithms/set/randomized_set.py diff --git a/set/set_covering.py b/algorithms/set/set_covering.py similarity index 100% rename from set/set_covering.py rename to algorithms/set/set_covering.py From 5224102d4ad414a12b03c6bcb3c7a98818a89fb2 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 14:55:05 -0700 Subject: [PATCH 019/302] reorganize sort --- algorithms/sort/__init__.py | 8 ++++++++ {sort => algorithms/sort}/bubble_sort.py | 0 {sort => algorithms/sort}/comb_sort.py | 0 {sort => algorithms/sort}/counting_sort.py | 0 {sort => algorithms/sort}/heap_sort.py | 0 {sort => algorithms/sort}/insertion_sort.py | 0 {sort => algorithms/sort}/meeting_rooms.py | 0 {sort => algorithms/sort}/merge_sort.py | 0 {sort => algorithms/sort}/quick_sort.py | 0 {sort => algorithms/sort}/selection_sort.py | 0 {sort => algorithms/sort}/sort_colors.py | 0 {sort => algorithms/sort}/topsort.py | 0 {sort => algorithms/sort}/wiggle_sort.py | 0 sort/__init__.py | 0 tests/test_sort.py | 18 ++++++++++-------- 15 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 algorithms/sort/__init__.py rename {sort => algorithms/sort}/bubble_sort.py (100%) rename {sort => algorithms/sort}/comb_sort.py (100%) rename {sort => algorithms/sort}/counting_sort.py (100%) rename {sort => algorithms/sort}/heap_sort.py (100%) rename {sort => algorithms/sort}/insertion_sort.py (100%) rename {sort => algorithms/sort}/meeting_rooms.py (100%) rename {sort => algorithms/sort}/merge_sort.py (100%) rename {sort => algorithms/sort}/quick_sort.py (100%) rename {sort => algorithms/sort}/selection_sort.py (100%) rename {sort => algorithms/sort}/sort_colors.py (100%) rename {sort => algorithms/sort}/topsort.py (100%) rename {sort => algorithms/sort}/wiggle_sort.py (100%) delete mode 100644 sort/__init__.py diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py new file mode 100644 index 000000000..20a3cf326 --- /dev/null +++ b/algorithms/sort/__init__.py @@ -0,0 +1,8 @@ +from .bubble_sort import * +from .comb_sort import * +from .counting_sort import * +from .heap_sort import * +from .insertion_sort import * +from .merge_sort import * +from .quick_sort import * +from .selection_sort import * diff --git a/sort/bubble_sort.py b/algorithms/sort/bubble_sort.py similarity index 100% rename from sort/bubble_sort.py rename to algorithms/sort/bubble_sort.py diff --git a/sort/comb_sort.py b/algorithms/sort/comb_sort.py similarity index 100% rename from sort/comb_sort.py rename to algorithms/sort/comb_sort.py diff --git a/sort/counting_sort.py b/algorithms/sort/counting_sort.py similarity index 100% rename from sort/counting_sort.py rename to algorithms/sort/counting_sort.py diff --git a/sort/heap_sort.py b/algorithms/sort/heap_sort.py similarity index 100% rename from sort/heap_sort.py rename to algorithms/sort/heap_sort.py diff --git a/sort/insertion_sort.py b/algorithms/sort/insertion_sort.py similarity index 100% rename from sort/insertion_sort.py rename to algorithms/sort/insertion_sort.py diff --git a/sort/meeting_rooms.py b/algorithms/sort/meeting_rooms.py similarity index 100% rename from sort/meeting_rooms.py rename to algorithms/sort/meeting_rooms.py diff --git a/sort/merge_sort.py b/algorithms/sort/merge_sort.py similarity index 100% rename from sort/merge_sort.py rename to algorithms/sort/merge_sort.py diff --git a/sort/quick_sort.py b/algorithms/sort/quick_sort.py similarity index 100% rename from sort/quick_sort.py rename to algorithms/sort/quick_sort.py diff --git a/sort/selection_sort.py b/algorithms/sort/selection_sort.py similarity index 100% rename from sort/selection_sort.py rename to algorithms/sort/selection_sort.py diff --git a/sort/sort_colors.py b/algorithms/sort/sort_colors.py similarity index 100% rename from sort/sort_colors.py rename to algorithms/sort/sort_colors.py diff --git a/sort/topsort.py b/algorithms/sort/topsort.py similarity index 100% rename from sort/topsort.py rename to algorithms/sort/topsort.py diff --git a/sort/wiggle_sort.py b/algorithms/sort/wiggle_sort.py similarity index 100% rename from sort/wiggle_sort.py rename to algorithms/sort/wiggle_sort.py diff --git a/sort/__init__.py b/sort/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_sort.py b/tests/test_sort.py index 30f27621c..07d13c8f3 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -1,11 +1,13 @@ -from sort.bubble_sort import bubble_sort -from sort.comb_sort import comb_sort -from sort.counting_sort import counting_sort -from sort.heap_sort import max_heap_sort, min_heap_sort -from sort.insertion_sort import insertion_sort -from sort.merge_sort import merge_sort -from sort.quick_sort import quick_sort -from sort.selection_sort import selection_sort +from algorithms.sort import ( + bubble_sort, + comb_sort, + counting_sort, + max_heap_sort, min_heap_sort, + insertion_sort, + merge_sort, + quick_sort, + selection_sort +) import unittest From 0f0ff08a9952a8a690c200c3ef7e52edc381146f Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 15:01:24 -0700 Subject: [PATCH 020/302] reorganize stack --- algorithms/stack/__init__.py | 10 ++++++++++ {stack => algorithms/stack}/is_consecutive.py | 0 {stack => algorithms/stack}/is_sorted.py | 0 .../stack}/longest_abs_path.py | 0 {stack => algorithms/stack}/ordered_stack.py | 0 {stack => algorithms/stack}/remove_min.py | 0 {stack => algorithms/stack}/simplify_path.py | 0 {stack => algorithms/stack}/stack.py | 0 {stack => algorithms/stack}/stutter.py | 0 {stack => algorithms/stack}/switch_pairs.py | 0 .../stack}/valid_parenthesis.py | 0 stack/__init__.py | 1 - tests/test_stack.py | 20 ++++++++++--------- 13 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 algorithms/stack/__init__.py rename {stack => algorithms/stack}/is_consecutive.py (100%) rename {stack => algorithms/stack}/is_sorted.py (100%) rename {stack => algorithms/stack}/longest_abs_path.py (100%) rename {stack => algorithms/stack}/ordered_stack.py (100%) rename {stack => algorithms/stack}/remove_min.py (100%) rename {stack => algorithms/stack}/simplify_path.py (100%) rename {stack => algorithms/stack}/stack.py (100%) rename {stack => algorithms/stack}/stutter.py (100%) rename {stack => algorithms/stack}/switch_pairs.py (100%) rename {stack => algorithms/stack}/valid_parenthesis.py (100%) delete mode 100644 stack/__init__.py diff --git a/algorithms/stack/__init__.py b/algorithms/stack/__init__.py new file mode 100644 index 000000000..4e8d0603f --- /dev/null +++ b/algorithms/stack/__init__.py @@ -0,0 +1,10 @@ +from .stack import * +from .is_consecutive import * +from .is_sorted import * +from .remove_min import * +from .stutter import * +from .switch_pairs import * +from .valid_parenthesis import * +from .simplify_path import * +from .stack import * +from .ordered_stack import * diff --git a/stack/is_consecutive.py b/algorithms/stack/is_consecutive.py similarity index 100% rename from stack/is_consecutive.py rename to algorithms/stack/is_consecutive.py diff --git a/stack/is_sorted.py b/algorithms/stack/is_sorted.py similarity index 100% rename from stack/is_sorted.py rename to algorithms/stack/is_sorted.py diff --git a/stack/longest_abs_path.py b/algorithms/stack/longest_abs_path.py similarity index 100% rename from stack/longest_abs_path.py rename to algorithms/stack/longest_abs_path.py diff --git a/stack/ordered_stack.py b/algorithms/stack/ordered_stack.py similarity index 100% rename from stack/ordered_stack.py rename to algorithms/stack/ordered_stack.py diff --git a/stack/remove_min.py b/algorithms/stack/remove_min.py similarity index 100% rename from stack/remove_min.py rename to algorithms/stack/remove_min.py diff --git a/stack/simplify_path.py b/algorithms/stack/simplify_path.py similarity index 100% rename from stack/simplify_path.py rename to algorithms/stack/simplify_path.py diff --git a/stack/stack.py b/algorithms/stack/stack.py similarity index 100% rename from stack/stack.py rename to algorithms/stack/stack.py diff --git a/stack/stutter.py b/algorithms/stack/stutter.py similarity index 100% rename from stack/stutter.py rename to algorithms/stack/stutter.py diff --git a/stack/switch_pairs.py b/algorithms/stack/switch_pairs.py similarity index 100% rename from stack/switch_pairs.py rename to algorithms/stack/switch_pairs.py diff --git a/stack/valid_parenthesis.py b/algorithms/stack/valid_parenthesis.py similarity index 100% rename from stack/valid_parenthesis.py rename to algorithms/stack/valid_parenthesis.py diff --git a/stack/__init__.py b/stack/__init__.py deleted file mode 100644 index 843a7582a..000000000 --- a/stack/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .stack import * diff --git a/tests/test_stack.py b/tests/test_stack.py index e3b85d414..d04b27f14 100644 --- a/tests/test_stack.py +++ b/tests/test_stack.py @@ -1,12 +1,14 @@ -from stack.is_consecutive import first_is_consecutive, second_is_consecutive -from stack.is_sorted import is_sorted -from stack.remove_min import remove_min -from stack.stutter import first_stutter, second_stutter -from stack.switch_pairs import first_switch_pairs, second_switch_pairs -from stack.valid_parenthesis import is_valid -from stack.simplify_path import simplify_path -from stack.stack import ArrayStack, LinkedListStack -from stack.ordered_stack import OrderedStack +from algorithms.stack import ( + first_is_consecutive, second_is_consecutive, + is_sorted, + remove_min, + first_stutter, second_stutter, + first_switch_pairs, second_switch_pairs, + is_valid, + simplify_path, + ArrayStack, LinkedListStack, + OrderedStack +) import unittest class TestSuite(unittest.TestCase): From 8fdc37b5630364f901a8fe3054054230fd7b8a95 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 15:18:43 -0700 Subject: [PATCH 021/302] reorganize strings --- algorithms/strings/__init__.py | 23 ++++++++ {strings => algorithms/strings}/add_binary.py | 0 .../strings}/breaking_bad.py | 0 .../strings}/decode_string.py | 0 .../strings}/delete_reoccurring.py | 0 .../strings}/domain_extractor.py | 0 .../strings}/encode_decode.py | 0 {strings => algorithms/strings}/fizzbuzz.py | 0 .../strings}/group_anagrams.py | 0 .../strings}/int_to_roman.py | 0 .../strings}/is_palindrome.py | 0 {strings => algorithms/strings}/is_rotated.py | 0 .../strings}/license_number.py | 0 .../strings}/make_sentence.py | 0 .../strings}/merge_string_checker.py | 0 .../strings}/multiply_strings.py | 0 .../strings}/one_edit_distance.py | 0 {strings => algorithms/strings}/rabin_karp.py | 0 .../strings}/reverse_string.py | 0 .../strings}/reverse_vowel.py | 0 .../strings}/reverse_words.py | 0 .../strings}/roman_to_int.py | 0 .../strings}/strip_url_params.py | 0 .../strings}/validate_coordinates.py | 0 .../strings}/word_squares.py | 0 tests/test_strings.py | 53 ++++++++++--------- 26 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 algorithms/strings/__init__.py rename {strings => algorithms/strings}/add_binary.py (100%) rename {strings => algorithms/strings}/breaking_bad.py (100%) rename {strings => algorithms/strings}/decode_string.py (100%) rename {strings => algorithms/strings}/delete_reoccurring.py (100%) rename {strings => algorithms/strings}/domain_extractor.py (100%) rename {strings => algorithms/strings}/encode_decode.py (100%) rename {strings => algorithms/strings}/fizzbuzz.py (100%) rename {strings => algorithms/strings}/group_anagrams.py (100%) rename {strings => algorithms/strings}/int_to_roman.py (100%) rename {strings => algorithms/strings}/is_palindrome.py (100%) rename {strings => algorithms/strings}/is_rotated.py (100%) rename {strings => algorithms/strings}/license_number.py (100%) rename {strings => algorithms/strings}/make_sentence.py (100%) rename {strings => algorithms/strings}/merge_string_checker.py (100%) rename {strings => algorithms/strings}/multiply_strings.py (100%) rename {strings => algorithms/strings}/one_edit_distance.py (100%) rename {strings => algorithms/strings}/rabin_karp.py (100%) rename {strings => algorithms/strings}/reverse_string.py (100%) rename {strings => algorithms/strings}/reverse_vowel.py (100%) rename {strings => algorithms/strings}/reverse_words.py (100%) rename {strings => algorithms/strings}/roman_to_int.py (100%) rename {strings => algorithms/strings}/strip_url_params.py (100%) rename {strings => algorithms/strings}/validate_coordinates.py (100%) rename {strings => algorithms/strings}/word_squares.py (100%) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py new file mode 100644 index 000000000..b4d1bb4c0 --- /dev/null +++ b/algorithms/strings/__init__.py @@ -0,0 +1,23 @@ +from .add_binary import * +from .breaking_bad import * +from .decode_string import * +from .delete_reoccurring import * +from .domain_extractor import * +from .encode_decode import * +from .group_anagrams import * +from .int_to_roman import * +from .is_palindrome import * +from .is_rotated import * +from .license_number import * +from .make_sentence import * +from .merge_string_checker import * +from .multiply_strings import * +from .one_edit_distance import * +from .rabin_karp import * +from .reverse_string import * +from .reverse_vowel import * +from .reverse_words import * +from .roman_to_int import * +from .strip_url_params import * +from .validate_coordinates import * +from .word_squares import * diff --git a/strings/add_binary.py b/algorithms/strings/add_binary.py similarity index 100% rename from strings/add_binary.py rename to algorithms/strings/add_binary.py diff --git a/strings/breaking_bad.py b/algorithms/strings/breaking_bad.py similarity index 100% rename from strings/breaking_bad.py rename to algorithms/strings/breaking_bad.py diff --git a/strings/decode_string.py b/algorithms/strings/decode_string.py similarity index 100% rename from strings/decode_string.py rename to algorithms/strings/decode_string.py diff --git a/strings/delete_reoccurring.py b/algorithms/strings/delete_reoccurring.py similarity index 100% rename from strings/delete_reoccurring.py rename to algorithms/strings/delete_reoccurring.py diff --git a/strings/domain_extractor.py b/algorithms/strings/domain_extractor.py similarity index 100% rename from strings/domain_extractor.py rename to algorithms/strings/domain_extractor.py diff --git a/strings/encode_decode.py b/algorithms/strings/encode_decode.py similarity index 100% rename from strings/encode_decode.py rename to algorithms/strings/encode_decode.py diff --git a/strings/fizzbuzz.py b/algorithms/strings/fizzbuzz.py similarity index 100% rename from strings/fizzbuzz.py rename to algorithms/strings/fizzbuzz.py diff --git a/strings/group_anagrams.py b/algorithms/strings/group_anagrams.py similarity index 100% rename from strings/group_anagrams.py rename to algorithms/strings/group_anagrams.py diff --git a/strings/int_to_roman.py b/algorithms/strings/int_to_roman.py similarity index 100% rename from strings/int_to_roman.py rename to algorithms/strings/int_to_roman.py diff --git a/strings/is_palindrome.py b/algorithms/strings/is_palindrome.py similarity index 100% rename from strings/is_palindrome.py rename to algorithms/strings/is_palindrome.py diff --git a/strings/is_rotated.py b/algorithms/strings/is_rotated.py similarity index 100% rename from strings/is_rotated.py rename to algorithms/strings/is_rotated.py diff --git a/strings/license_number.py b/algorithms/strings/license_number.py similarity index 100% rename from strings/license_number.py rename to algorithms/strings/license_number.py diff --git a/strings/make_sentence.py b/algorithms/strings/make_sentence.py similarity index 100% rename from strings/make_sentence.py rename to algorithms/strings/make_sentence.py diff --git a/strings/merge_string_checker.py b/algorithms/strings/merge_string_checker.py similarity index 100% rename from strings/merge_string_checker.py rename to algorithms/strings/merge_string_checker.py diff --git a/strings/multiply_strings.py b/algorithms/strings/multiply_strings.py similarity index 100% rename from strings/multiply_strings.py rename to algorithms/strings/multiply_strings.py diff --git a/strings/one_edit_distance.py b/algorithms/strings/one_edit_distance.py similarity index 100% rename from strings/one_edit_distance.py rename to algorithms/strings/one_edit_distance.py diff --git a/strings/rabin_karp.py b/algorithms/strings/rabin_karp.py similarity index 100% rename from strings/rabin_karp.py rename to algorithms/strings/rabin_karp.py diff --git a/strings/reverse_string.py b/algorithms/strings/reverse_string.py similarity index 100% rename from strings/reverse_string.py rename to algorithms/strings/reverse_string.py diff --git a/strings/reverse_vowel.py b/algorithms/strings/reverse_vowel.py similarity index 100% rename from strings/reverse_vowel.py rename to algorithms/strings/reverse_vowel.py diff --git a/strings/reverse_words.py b/algorithms/strings/reverse_words.py similarity index 100% rename from strings/reverse_words.py rename to algorithms/strings/reverse_words.py diff --git a/strings/roman_to_int.py b/algorithms/strings/roman_to_int.py similarity index 100% rename from strings/roman_to_int.py rename to algorithms/strings/roman_to_int.py diff --git a/strings/strip_url_params.py b/algorithms/strings/strip_url_params.py similarity index 100% rename from strings/strip_url_params.py rename to algorithms/strings/strip_url_params.py diff --git a/strings/validate_coordinates.py b/algorithms/strings/validate_coordinates.py similarity index 100% rename from strings/validate_coordinates.py rename to algorithms/strings/validate_coordinates.py diff --git a/strings/word_squares.py b/algorithms/strings/word_squares.py similarity index 100% rename from strings/word_squares.py rename to algorithms/strings/word_squares.py diff --git a/tests/test_strings.py b/tests/test_strings.py index c0aa28334..31e0d3ed5 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -1,27 +1,30 @@ -from strings.add_binary import add_binary -from strings.breaking_bad import match_symbol, match_symbol_1, bracket -from strings.decode_string import decode_string -from strings.delete_reoccurring import delete_reoccurring_characters -from strings.domain_extractor import domain_name_1, domain_name_2 -from strings.encode_decode import encode, decode -from strings.group_anagrams import group_anagrams -from strings.int_to_roman import int_to_roman -from strings.is_palindrome import is_palindrome, is_palindrome_reverse, \ -is_palindrome_two_pointer, is_palindrome_stack -from strings.is_rotated import is_rotated -from strings.license_number import license_number -from strings.make_sentence import make_sentence -from strings.merge_string_checker import is_merge_recursive, is_merge_iterative -from strings.multiply_strings import multiply -from strings.one_edit_distance import is_one_edit, is_one_edit2 -from strings.rabin_karp import rabin_karp -from strings.reverse_string import * -from strings.reverse_vowel import reverse_vowel -from strings.reverse_words import reverse_words -from strings.roman_to_int import roman_to_int -from strings.strip_url_params import * -from strings.validate_coordinates import * -from strings.word_squares import word_squares +from algorithms.strings import ( + add_binary, + match_symbol, match_symbol_1, bracket, + decode_string, + delete_reoccurring_characters, + domain_name_1, domain_name_2, + encode, decode, + group_anagrams, + int_to_roman, + is_palindrome, is_palindrome_reverse, + is_palindrome_two_pointer, is_palindrome_stack, + is_rotated, + license_number, + make_sentence, + is_merge_recursive, is_merge_iterative, + multiply, + is_one_edit, is_one_edit2, + rabin_karp, + ultra_pythonic, iterative, recursive, pythonic, + reverse_vowel, + reverse_words, + roman_to_int, + strip_url_params1, strip_url_params2, strip_url_params3, + is_valid_coordinates_0, is_valid_coordinates_1, + is_valid_coordinates_regular_expression, + word_squares +) import unittest @@ -380,4 +383,4 @@ def test_word_squares(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From a8545b37740258a87ec443c51c0e05c819e70101 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 15:29:30 -0700 Subject: [PATCH 022/302] reorganize bit --- algorithms/bit/__init__.py | 15 +++++++++ .../bit}/add_bitwise_operator.py | 0 {bit => algorithms/bit}/bit_operation.py | 0 .../bit}/bytes_int_conversion.py | 0 {bit => algorithms/bit}/count_ones.py | 0 {bit => algorithms/bit}/find_difference.py | 0 .../bit}/find_missing_number.py | 0 .../bit}/has_alternative_bit.py | 0 {bit => algorithms/bit}/insert_bit.py | 0 {bit => algorithms/bit}/power_of_two.py | 0 {bit => algorithms/bit}/remove_bit.py | 0 {bit => algorithms/bit}/reverse_bits.py | 0 {bit => algorithms/bit}/single_number.py | 0 {bit => algorithms/bit}/single_number2.py | 16 ---------- {bit => algorithms/bit}/single_number3.py | 0 {bit => algorithms/bit}/subsets.py | 0 {bit => algorithms/bit}/swap_pair.py | 0 bit/__init__.py | 0 tests/test_bit.py | 32 ++++++++++--------- 19 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 algorithms/bit/__init__.py rename {bit => algorithms/bit}/add_bitwise_operator.py (100%) rename {bit => algorithms/bit}/bit_operation.py (100%) rename {bit => algorithms/bit}/bytes_int_conversion.py (100%) rename {bit => algorithms/bit}/count_ones.py (100%) rename {bit => algorithms/bit}/find_difference.py (100%) rename {bit => algorithms/bit}/find_missing_number.py (100%) rename {bit => algorithms/bit}/has_alternative_bit.py (100%) rename {bit => algorithms/bit}/insert_bit.py (100%) rename {bit => algorithms/bit}/power_of_two.py (100%) rename {bit => algorithms/bit}/remove_bit.py (100%) rename {bit => algorithms/bit}/reverse_bits.py (100%) rename {bit => algorithms/bit}/single_number.py (100%) rename {bit => algorithms/bit}/single_number2.py (71%) rename {bit => algorithms/bit}/single_number3.py (100%) rename {bit => algorithms/bit}/subsets.py (100%) rename {bit => algorithms/bit}/swap_pair.py (100%) delete mode 100644 bit/__init__.py diff --git a/algorithms/bit/__init__.py b/algorithms/bit/__init__.py new file mode 100644 index 000000000..7cd175f6a --- /dev/null +++ b/algorithms/bit/__init__.py @@ -0,0 +1,15 @@ +from .add_bitwise_operator import * +from .count_ones import * +from .find_missing_number import * +from .power_of_two import * +from .reverse_bits import * +from .single_number import * +from .single_number2 import * +from .single_number3 import * +from .subsets import * +from .bit_operation import * +from .swap_pair import * +from .find_difference import * +from .has_alternative_bit import * +from .insert_bit import * +from .remove_bit import * diff --git a/bit/add_bitwise_operator.py b/algorithms/bit/add_bitwise_operator.py similarity index 100% rename from bit/add_bitwise_operator.py rename to algorithms/bit/add_bitwise_operator.py diff --git a/bit/bit_operation.py b/algorithms/bit/bit_operation.py similarity index 100% rename from bit/bit_operation.py rename to algorithms/bit/bit_operation.py diff --git a/bit/bytes_int_conversion.py b/algorithms/bit/bytes_int_conversion.py similarity index 100% rename from bit/bytes_int_conversion.py rename to algorithms/bit/bytes_int_conversion.py diff --git a/bit/count_ones.py b/algorithms/bit/count_ones.py similarity index 100% rename from bit/count_ones.py rename to algorithms/bit/count_ones.py diff --git a/bit/find_difference.py b/algorithms/bit/find_difference.py similarity index 100% rename from bit/find_difference.py rename to algorithms/bit/find_difference.py diff --git a/bit/find_missing_number.py b/algorithms/bit/find_missing_number.py similarity index 100% rename from bit/find_missing_number.py rename to algorithms/bit/find_missing_number.py diff --git a/bit/has_alternative_bit.py b/algorithms/bit/has_alternative_bit.py similarity index 100% rename from bit/has_alternative_bit.py rename to algorithms/bit/has_alternative_bit.py diff --git a/bit/insert_bit.py b/algorithms/bit/insert_bit.py similarity index 100% rename from bit/insert_bit.py rename to algorithms/bit/insert_bit.py diff --git a/bit/power_of_two.py b/algorithms/bit/power_of_two.py similarity index 100% rename from bit/power_of_two.py rename to algorithms/bit/power_of_two.py diff --git a/bit/remove_bit.py b/algorithms/bit/remove_bit.py similarity index 100% rename from bit/remove_bit.py rename to algorithms/bit/remove_bit.py diff --git a/bit/reverse_bits.py b/algorithms/bit/reverse_bits.py similarity index 100% rename from bit/reverse_bits.py rename to algorithms/bit/reverse_bits.py diff --git a/bit/single_number.py b/algorithms/bit/single_number.py similarity index 100% rename from bit/single_number.py rename to algorithms/bit/single_number.py diff --git a/bit/single_number2.py b/algorithms/bit/single_number2.py similarity index 71% rename from bit/single_number2.py rename to algorithms/bit/single_number2.py index 9aff72cfe..2f0e36c59 100644 --- a/bit/single_number2.py +++ b/algorithms/bit/single_number2.py @@ -17,22 +17,6 @@ the remaining should be the exact bit of the single number. In this way, you get the 32 bits of the single number. """ -def single_number(nums): - """ - :type nums: List[int] - :rtype: int - """ - res = 0 - for i in range(0, 32): - count = 0 - for num in nums: - if (num >> i) & 1: - count += 1 - res |= ((count % 3) << i) - if res >= 2**31: - res -= 2**32 - return res - # Another awesome answer def single_number2(nums): diff --git a/bit/single_number3.py b/algorithms/bit/single_number3.py similarity index 100% rename from bit/single_number3.py rename to algorithms/bit/single_number3.py diff --git a/bit/subsets.py b/algorithms/bit/subsets.py similarity index 100% rename from bit/subsets.py rename to algorithms/bit/subsets.py diff --git a/bit/swap_pair.py b/algorithms/bit/swap_pair.py similarity index 100% rename from bit/swap_pair.py rename to algorithms/bit/swap_pair.py diff --git a/bit/__init__.py b/bit/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_bit.py b/tests/test_bit.py index 33d80d9b5..01290c2f3 100644 --- a/tests/test_bit.py +++ b/tests/test_bit.py @@ -1,18 +1,20 @@ -from bit.add_bitwise_operator import add_bitwise_operator -from bit.count_ones import count_ones_iter, count_ones_recur -from bit.find_missing_number import find_missing_number, find_missing_number2 -from bit.power_of_two import is_power_of_two -from bit.reverse_bits import reverse_bits -from bit.single_number import single_number -from bit.single_number2 import single_number2 -from bit.single_number3 import single_number3 -from bit.subsets import subsets -from bit.bit_operation import get_bit, set_bit, clear_bit, update_bit -from bit.swap_pair import swap_pair -from bit.find_difference import find_difference -from bit.has_alternative_bit import has_alternative_bit, has_alternative_bit_fast -from bit.insert_bit import insert_one_bit, insert_mult_bits -from bit.remove_bit import remove_bit +from algorithms.bit import ( + add_bitwise_operator, + count_ones_iter, count_ones_recur, + find_missing_number, find_missing_number2, + is_power_of_two, + reverse_bits, + single_number, + single_number2, + single_number3, + subsets, + get_bit, set_bit, clear_bit, update_bit, + swap_pair, + find_difference, + has_alternative_bit, has_alternative_bit_fast, + insert_one_bit, insert_mult_bits, + remove_bit +) import unittest import random From 844a50456627943ec9c55fd604cdb5316de41443 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 15:30:47 -0700 Subject: [PATCH 023/302] reorganize tree --- {tree => algorithms/tree}/avl/__init__.py | 0 {tree => algorithms/tree}/avl/avl.py | 0 {tree => algorithms/tree}/binary_tree_paths.py | 0 {tree => algorithms/tree}/bintree2list.py | 0 {tree => algorithms/tree}/bst/BSTIterator.py | 0 {tree => algorithms/tree}/bst/array2bst.py | 0 {tree => algorithms/tree}/bst/bst.py | 0 {tree => algorithms/tree}/bst/bst_closest_value.py | 0 {tree => algorithms/tree}/bst/count_left_node.py | 0 {tree => algorithms/tree}/bst/delete_node.py | 0 {tree => algorithms/tree}/bst/depth_sum.py | 0 {tree => algorithms/tree}/bst/height.py | 0 {tree => algorithms/tree}/bst/is_bst.py | 0 {tree => algorithms/tree}/bst/kth_smallest.py | 0 {tree => algorithms/tree}/bst/lowest_common_ancestor.py | 0 {tree => algorithms/tree}/bst/num_empty.py | 0 {tree => algorithms/tree}/bst/predecessor.py | 0 {tree => algorithms/tree}/bst/serialize_deserialize.py | 0 {tree => algorithms/tree}/bst/successor.py | 0 {tree => algorithms/tree}/bst/unique_bst.py | 0 {tree => algorithms/tree}/deepest_left.py | 0 {tree => algorithms/tree}/invert_tree.py | 0 {tree => algorithms/tree}/is_balanced.py | 0 {tree => algorithms/tree}/is_subtree.py | 0 {tree => algorithms/tree}/is_symmetric.py | 0 {tree => algorithms/tree}/longest_consecutive.py | 0 {tree => algorithms/tree}/lowest_common_ancestor.py | 0 {tree => algorithms/tree}/max_height.py | 0 {tree => algorithms/tree}/max_path_sum.py | 0 {tree => algorithms/tree}/min_height.py | 0 {tree => algorithms/tree}/path_sum.py | 0 {tree => algorithms/tree}/path_sum2.py | 0 {tree => algorithms/tree}/pretty_print.py | 0 {tree => algorithms/tree}/red_black_tree/red_black_tree.py | 0 {tree => algorithms/tree}/same_tree.py | 0 {tree => algorithms/tree}/segment_tree/segment_tree.py | 0 {tree => algorithms/tree}/traversal/inorder.py | 0 {tree => algorithms/tree}/traversal/level_order.py | 0 {tree => algorithms/tree}/traversal/zigzag.py | 0 {tree => algorithms/tree}/tree.py | 0 {tree => algorithms/tree}/trie/add_and_search.py | 0 {tree => algorithms/tree}/trie/trie.py | 0 42 files changed, 0 insertions(+), 0 deletions(-) rename {tree => algorithms/tree}/avl/__init__.py (100%) rename {tree => algorithms/tree}/avl/avl.py (100%) rename {tree => algorithms/tree}/binary_tree_paths.py (100%) rename {tree => algorithms/tree}/bintree2list.py (100%) rename {tree => algorithms/tree}/bst/BSTIterator.py (100%) rename {tree => algorithms/tree}/bst/array2bst.py (100%) rename {tree => algorithms/tree}/bst/bst.py (100%) rename {tree => algorithms/tree}/bst/bst_closest_value.py (100%) rename {tree => algorithms/tree}/bst/count_left_node.py (100%) rename {tree => algorithms/tree}/bst/delete_node.py (100%) rename {tree => algorithms/tree}/bst/depth_sum.py (100%) rename {tree => algorithms/tree}/bst/height.py (100%) rename {tree => algorithms/tree}/bst/is_bst.py (100%) rename {tree => algorithms/tree}/bst/kth_smallest.py (100%) rename {tree => algorithms/tree}/bst/lowest_common_ancestor.py (100%) rename {tree => algorithms/tree}/bst/num_empty.py (100%) rename {tree => algorithms/tree}/bst/predecessor.py (100%) rename {tree => algorithms/tree}/bst/serialize_deserialize.py (100%) rename {tree => algorithms/tree}/bst/successor.py (100%) rename {tree => algorithms/tree}/bst/unique_bst.py (100%) rename {tree => algorithms/tree}/deepest_left.py (100%) rename {tree => algorithms/tree}/invert_tree.py (100%) rename {tree => algorithms/tree}/is_balanced.py (100%) rename {tree => algorithms/tree}/is_subtree.py (100%) rename {tree => algorithms/tree}/is_symmetric.py (100%) rename {tree => algorithms/tree}/longest_consecutive.py (100%) rename {tree => algorithms/tree}/lowest_common_ancestor.py (100%) rename {tree => algorithms/tree}/max_height.py (100%) rename {tree => algorithms/tree}/max_path_sum.py (100%) rename {tree => algorithms/tree}/min_height.py (100%) rename {tree => algorithms/tree}/path_sum.py (100%) rename {tree => algorithms/tree}/path_sum2.py (100%) rename {tree => algorithms/tree}/pretty_print.py (100%) rename {tree => algorithms/tree}/red_black_tree/red_black_tree.py (100%) rename {tree => algorithms/tree}/same_tree.py (100%) rename {tree => algorithms/tree}/segment_tree/segment_tree.py (100%) rename {tree => algorithms/tree}/traversal/inorder.py (100%) rename {tree => algorithms/tree}/traversal/level_order.py (100%) rename {tree => algorithms/tree}/traversal/zigzag.py (100%) rename {tree => algorithms/tree}/tree.py (100%) rename {tree => algorithms/tree}/trie/add_and_search.py (100%) rename {tree => algorithms/tree}/trie/trie.py (100%) diff --git a/tree/avl/__init__.py b/algorithms/tree/avl/__init__.py similarity index 100% rename from tree/avl/__init__.py rename to algorithms/tree/avl/__init__.py diff --git a/tree/avl/avl.py b/algorithms/tree/avl/avl.py similarity index 100% rename from tree/avl/avl.py rename to algorithms/tree/avl/avl.py diff --git a/tree/binary_tree_paths.py b/algorithms/tree/binary_tree_paths.py similarity index 100% rename from tree/binary_tree_paths.py rename to algorithms/tree/binary_tree_paths.py diff --git a/tree/bintree2list.py b/algorithms/tree/bintree2list.py similarity index 100% rename from tree/bintree2list.py rename to algorithms/tree/bintree2list.py diff --git a/tree/bst/BSTIterator.py b/algorithms/tree/bst/BSTIterator.py similarity index 100% rename from tree/bst/BSTIterator.py rename to algorithms/tree/bst/BSTIterator.py diff --git a/tree/bst/array2bst.py b/algorithms/tree/bst/array2bst.py similarity index 100% rename from tree/bst/array2bst.py rename to algorithms/tree/bst/array2bst.py diff --git a/tree/bst/bst.py b/algorithms/tree/bst/bst.py similarity index 100% rename from tree/bst/bst.py rename to algorithms/tree/bst/bst.py diff --git a/tree/bst/bst_closest_value.py b/algorithms/tree/bst/bst_closest_value.py similarity index 100% rename from tree/bst/bst_closest_value.py rename to algorithms/tree/bst/bst_closest_value.py diff --git a/tree/bst/count_left_node.py b/algorithms/tree/bst/count_left_node.py similarity index 100% rename from tree/bst/count_left_node.py rename to algorithms/tree/bst/count_left_node.py diff --git a/tree/bst/delete_node.py b/algorithms/tree/bst/delete_node.py similarity index 100% rename from tree/bst/delete_node.py rename to algorithms/tree/bst/delete_node.py diff --git a/tree/bst/depth_sum.py b/algorithms/tree/bst/depth_sum.py similarity index 100% rename from tree/bst/depth_sum.py rename to algorithms/tree/bst/depth_sum.py diff --git a/tree/bst/height.py b/algorithms/tree/bst/height.py similarity index 100% rename from tree/bst/height.py rename to algorithms/tree/bst/height.py diff --git a/tree/bst/is_bst.py b/algorithms/tree/bst/is_bst.py similarity index 100% rename from tree/bst/is_bst.py rename to algorithms/tree/bst/is_bst.py diff --git a/tree/bst/kth_smallest.py b/algorithms/tree/bst/kth_smallest.py similarity index 100% rename from tree/bst/kth_smallest.py rename to algorithms/tree/bst/kth_smallest.py diff --git a/tree/bst/lowest_common_ancestor.py b/algorithms/tree/bst/lowest_common_ancestor.py similarity index 100% rename from tree/bst/lowest_common_ancestor.py rename to algorithms/tree/bst/lowest_common_ancestor.py diff --git a/tree/bst/num_empty.py b/algorithms/tree/bst/num_empty.py similarity index 100% rename from tree/bst/num_empty.py rename to algorithms/tree/bst/num_empty.py diff --git a/tree/bst/predecessor.py b/algorithms/tree/bst/predecessor.py similarity index 100% rename from tree/bst/predecessor.py rename to algorithms/tree/bst/predecessor.py diff --git a/tree/bst/serialize_deserialize.py b/algorithms/tree/bst/serialize_deserialize.py similarity index 100% rename from tree/bst/serialize_deserialize.py rename to algorithms/tree/bst/serialize_deserialize.py diff --git a/tree/bst/successor.py b/algorithms/tree/bst/successor.py similarity index 100% rename from tree/bst/successor.py rename to algorithms/tree/bst/successor.py diff --git a/tree/bst/unique_bst.py b/algorithms/tree/bst/unique_bst.py similarity index 100% rename from tree/bst/unique_bst.py rename to algorithms/tree/bst/unique_bst.py diff --git a/tree/deepest_left.py b/algorithms/tree/deepest_left.py similarity index 100% rename from tree/deepest_left.py rename to algorithms/tree/deepest_left.py diff --git a/tree/invert_tree.py b/algorithms/tree/invert_tree.py similarity index 100% rename from tree/invert_tree.py rename to algorithms/tree/invert_tree.py diff --git a/tree/is_balanced.py b/algorithms/tree/is_balanced.py similarity index 100% rename from tree/is_balanced.py rename to algorithms/tree/is_balanced.py diff --git a/tree/is_subtree.py b/algorithms/tree/is_subtree.py similarity index 100% rename from tree/is_subtree.py rename to algorithms/tree/is_subtree.py diff --git a/tree/is_symmetric.py b/algorithms/tree/is_symmetric.py similarity index 100% rename from tree/is_symmetric.py rename to algorithms/tree/is_symmetric.py diff --git a/tree/longest_consecutive.py b/algorithms/tree/longest_consecutive.py similarity index 100% rename from tree/longest_consecutive.py rename to algorithms/tree/longest_consecutive.py diff --git a/tree/lowest_common_ancestor.py b/algorithms/tree/lowest_common_ancestor.py similarity index 100% rename from tree/lowest_common_ancestor.py rename to algorithms/tree/lowest_common_ancestor.py diff --git a/tree/max_height.py b/algorithms/tree/max_height.py similarity index 100% rename from tree/max_height.py rename to algorithms/tree/max_height.py diff --git a/tree/max_path_sum.py b/algorithms/tree/max_path_sum.py similarity index 100% rename from tree/max_path_sum.py rename to algorithms/tree/max_path_sum.py diff --git a/tree/min_height.py b/algorithms/tree/min_height.py similarity index 100% rename from tree/min_height.py rename to algorithms/tree/min_height.py diff --git a/tree/path_sum.py b/algorithms/tree/path_sum.py similarity index 100% rename from tree/path_sum.py rename to algorithms/tree/path_sum.py diff --git a/tree/path_sum2.py b/algorithms/tree/path_sum2.py similarity index 100% rename from tree/path_sum2.py rename to algorithms/tree/path_sum2.py diff --git a/tree/pretty_print.py b/algorithms/tree/pretty_print.py similarity index 100% rename from tree/pretty_print.py rename to algorithms/tree/pretty_print.py diff --git a/tree/red_black_tree/red_black_tree.py b/algorithms/tree/red_black_tree/red_black_tree.py similarity index 100% rename from tree/red_black_tree/red_black_tree.py rename to algorithms/tree/red_black_tree/red_black_tree.py diff --git a/tree/same_tree.py b/algorithms/tree/same_tree.py similarity index 100% rename from tree/same_tree.py rename to algorithms/tree/same_tree.py diff --git a/tree/segment_tree/segment_tree.py b/algorithms/tree/segment_tree/segment_tree.py similarity index 100% rename from tree/segment_tree/segment_tree.py rename to algorithms/tree/segment_tree/segment_tree.py diff --git a/tree/traversal/inorder.py b/algorithms/tree/traversal/inorder.py similarity index 100% rename from tree/traversal/inorder.py rename to algorithms/tree/traversal/inorder.py diff --git a/tree/traversal/level_order.py b/algorithms/tree/traversal/level_order.py similarity index 100% rename from tree/traversal/level_order.py rename to algorithms/tree/traversal/level_order.py diff --git a/tree/traversal/zigzag.py b/algorithms/tree/traversal/zigzag.py similarity index 100% rename from tree/traversal/zigzag.py rename to algorithms/tree/traversal/zigzag.py diff --git a/tree/tree.py b/algorithms/tree/tree.py similarity index 100% rename from tree/tree.py rename to algorithms/tree/tree.py diff --git a/tree/trie/add_and_search.py b/algorithms/tree/trie/add_and_search.py similarity index 100% rename from tree/trie/add_and_search.py rename to algorithms/tree/trie/add_and_search.py diff --git a/tree/trie/trie.py b/algorithms/tree/trie/trie.py similarity index 100% rename from tree/trie/trie.py rename to algorithms/tree/trie/trie.py From e584a1d093117d87da1f7ced2c528383a1e5ffe4 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 15:31:55 -0700 Subject: [PATCH 024/302] reorganize other files --- {calculator => algorithms/calculator}/math_parser.py | 0 {union-find => algorithms/union-find}/count_islands.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {calculator => algorithms/calculator}/math_parser.py (100%) rename {union-find => algorithms/union-find}/count_islands.py (100%) diff --git a/calculator/math_parser.py b/algorithms/calculator/math_parser.py similarity index 100% rename from calculator/math_parser.py rename to algorithms/calculator/math_parser.py diff --git a/union-find/count_islands.py b/algorithms/union-find/count_islands.py similarity index 100% rename from union-find/count_islands.py rename to algorithms/union-find/count_islands.py From 4e1ecd16249a86623b5e58cf7c79cab3899f6ac4 Mon Sep 17 00:00:00 2001 From: danghai Date: Tue, 29 May 2018 15:43:22 -0700 Subject: [PATCH 025/302] README.md: Update python packaging following reorganize --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fce6c05a3..1f518e63e 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ If you want to use the API algorithms in your code, it is as simple as: You can test by creating a python file: (Ex: use `merge_sort` in `sort`) ```python3 -from sort import merge_sort +from algorithms.sort import merge_sort if __name__ == "__main__": my_list = [1, 8, 3, 5, 6] - my_list = merge_sort.merge_sort(my_list) + my_list = merge_sort(my_list) print(my_list) ``` From 343e3984f23f73a9bddca412337e8cb0a8b1d7a2 Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Wed, 30 May 2018 23:40:50 +0900 Subject: [PATCH 026/302] Created README and CONTRIBUTING files in Japanese (#289) * Create CONTRIBUTING_JP.md * Create README_JP.md * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_JP.md --- CONTRIBUTING_JP.md | 61 +++++++++ README.md | 2 +- README_CN.md | 2 +- README_GE.md | 2 +- README_JP.md | 317 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 381 insertions(+), 3 deletions(-) create mode 100644 CONTRIBUTING_JP.md create mode 100644 README_JP.md diff --git a/CONTRIBUTING_JP.md b/CONTRIBUTING_JP.md new file mode 100644 index 000000000..a8e46c238 --- /dev/null +++ b/CONTRIBUTING_JP.md @@ -0,0 +1,61 @@ +# 貢献 + +私たちは、誰からもプルリクエストを歓迎します。このレポジトリに貢献をするためには[Code of Conduct](CODE_OF_CONDUCT.md)を従うことを同意しなければなりません。 + +## 始める + +* まずリポジトリを[フォーク][fork]し,次を使用してクローンします. + + git clone git@github.com:your-username/algorithms.git + +* その後,変更のためのブランチを作成します. 例えば: + * add_XXX : 新しいアルゴリズムやデータ構造を追加する場合 + * fix_XXX : 特定のアルゴリズムやデータ構造のbugを修正する場合 + * test_XXX : テストを作成する場合 + +以下の方法で貢献できます: +- レポジトリの新しいアルゴリズムを開発すること。 正しいセクションに保存してください(例: [array](array), [dp](dp), 等)。 どのセクションにも該当しない場合は、新しいセクションを作成します。 また、コードが正常に作動するかどうか確認してください。 +- 既存のアルゴリズムの最適化または改善。 +- 問題の他のソリューションを追加。 +- バグの検索と修正。 +- アルゴリズムをよりよく説明するための例を追加。 +- テストケースの追加。 + +## プルリクエスト +フォークにプッシュして[プルリクエストを送信します][pr]。 + +私たちは、検討した後、変更、改善、代替案を提案することもできます。 +あなたのプルリクエストが受け入れられる可能性が高くなる方法: + +* すべてのアルゴリズムは**Python 3**で開発されなければなりません。 +(まだPython 2で作成されたアルゴリズムがいくつかあります。これらをPython 3に転換する作業でスタートすることもできます。) +* きれいで理解しやすいコードを作成する。 +* コードに適切なコメントを残して[docstrings][docstr]にアルゴリズムが何をしているのか簡単に説明する。 +* 小さな例を通じて出力を説明する。 +* アルゴリズムのテストケースをいくつか含ませる。 +* [good commit message][commit]を書く。 + + +## イシュー +追加するアルゴリズムがあったり、既存のアルゴリズムにバグが発見された場合の[new issue][newissue]を提出してください。 新たなイシューを提出する前に重複を避けるために、[existing issues][issues]を確認してください。 また、現在のイシューを解決したり論議中のイシューに貢献することも考慮してください。 + +## コラボレータ +コラボレータには,どのようなヘルプや説明も求めることができます. + +[Keon Kim](https://github.com/keon) + +[Rahul Goswami](https://github.com/goswami-rahul) + +[Ankit Agarwal](https://github.com/ankit167) + +[Hai Hoang Dang](https://github.com/danghai) + +[Saad](https://github.com/SaadBenn) + +[fork]: https://help.github.com/articles/fork-a-repo/ +[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings +[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[pr]: https://github.com/keon/algorithms/compare/ +[newissue]: https://github.com/keon/algorithms/issues/new +[issue120]: https://github.com/keon/algorithms/issues/120 +[issues]: https://github.com/keon/algorithms/issues/ diff --git a/README.md b/README.md index fce6c05a3..4848622f2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -English | [简体中文](https://github.com/yunshuipiao/algorithms/blob/master/README_CN.md) | [Deutsch](README_GE.md) +English | [简体中文](https://github.com/yunshuipiao/algorithms/blob/master/README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) diff --git a/README_CN.md b/README_CN.md index c612cd522..dac345276 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -[English](https://github.com/yunshuipiao/algorithms/blob/master/README.md) | 简体中文 +[English](https://github.com/yunshuipiao/algorithms/blob/master/README.md) | 简体中文 | [日本語](README_JP.md) Python版数据结构和算法 ========================================= diff --git a/README_GE.md b/README_GE.md index af1b8b2c4..cb36b22a7 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](https://github.com/yunshuipiao/algorithms/blob/master/README_CN.md) | Deutsch +[English](README.md) | [简体中文](https://github.com/yunshuipiao/algorithms/blob/master/README_CN.md) | Deutsch | [日本語](README_JP.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) diff --git a/README_JP.md b/README_JP.md new file mode 100644 index 000000000..352d728fe --- /dev/null +++ b/README_JP.md @@ -0,0 +1,317 @@ +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 + +pythonのデータ構造とアルゴリズム +========================================= + +Python 3で開発された簡単で明確なデータ構造とアルゴリズムの例を紹介します。 + +## 貢献 +貢献に興味を持っていただきありがとうございます。 このプロジェクトに貢献する方法はたくさんあります。 + +[簡単にコミュニティへ貢献するには](CONTRIBUTING_JP.md) + +## テスト + +### unittestを使用 +すべてのテストを実行するには: + + $ python3 -m unittest discover tests + +特定のテストを実行するためには、(例: ソート): + + $ python3 -m unittest tests.test_sort + +### pytestを使用 +すべてのテストを実行するには: + + $ python3 -m pytest tests + +## インストール +自分のコードでAPIアルゴリズムを活用したい場合は、以下のコードで簡単に実行することができます。 + + $ pip3 install git+https://github.com/keon/algorithms + +Pythonファイルを作成してテストを行うことができます:(例:「sort」の「merge_sort」を使用) + +```python3 +from sort import merge_sort + +if __name__ == "__main__": + my_list = [1, 8, 3, 5, 6] + my_list = merge_sort.merge_sort(my_list) + print(my_list) +``` + +## 削除 +アルゴリズムを削除する場合は、次のコードで簡単に実行することができます: + + $ pip3 uninstall -y algorithms + +## アルゴリズムのリスト + +- [arrays : 配列](arrays) + - [delete_nth](arrays/delete_nth.py) + - [flatten](arrays/flatten.py) + - [garage](arrays/garage.py) + - [josephus_problem](arrays/josephus_problem.py) + - [longest_non_repeat](arrays/longest_non_repeat.py/) + - [merge_intervals](arrays/merge_intervals.py) + - [missing_ranges](arrays/missing_ranges.py) + - [plus_one](arrays/plus_one.py) + - [rotate_array](arrays/rotate_array.py) + - [summary_ranges](arrays/summary_ranges.py) + - [three_sum](arrays/three_sum.py) + - [two_sum](arrays/two_sum.py) + - [move_zeros_to_end](arrays/move_zeros_to_end.py) +- [backtrack : バックトラッキング](backtrack) + - [general_solution.md](backtrack/) + - [anagram](backtrack/anagram.py) + - [array_sum_combinations](backtrack/array_sum_combinations.py) + - [combination_sum](backtrack/combination_sum.py) + - [expression_add_operators](backtrack/expression_add_operators.py) + - [factor_combinations](backtrack/factor_combinations.py) + - [generate_abbreviations](backtrack/generate_abbreviations.py) + - [generate_parenthesis](backtrack/generate_parenthesis.py) + - [letter_combination](backtrack/letter_combination.py) + - [palindrome_partitioning](backtrack/palindrome_partitioning.py) + - [pattern_match](backtrack/pattern_match.py) + - [permute](backtrack/permute.py) + - [permute_unique](backtrack/permute_unique.py) + - [subsets](backtrack/subsets.py) + - [subsets_unique](backtrack/subsets_unique.py) +- [bfs : 幅優先探索](bfs) + - [shortest_distance_from_all_buildings](bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](bfs/word_ladder.py) +- [bit : ビット](bit) + - [bytes_int_conversion](bit/bytes_int_conversion.py) + - [count_ones](bit/count_ones.py) + - [find_missing_number](bit/find_missing_number.py) + - [power_of_two](bit/power_of_two.py) + - [reverse_bits](bit/reverse_bits.py) + - [single_number](bit/single_number.py) + - [single_number2](bit/single_number2.py) + - [single_number3](bit/single_number3.py) + - [subsets](bit/subsets.py) + - [add_bitwise_operator](bit/add_bitwise_operator.py) + - [bit_operation](bit/bit_operation.py) + - [swap_pair](bit/swap_pair.py) + - [find_difference](bit/find_difference.py) + - [has_alternative_bit](bit/has_alternative_bit.py) + - [insert_bit](bit/insert_bit.py) + - [remove_bit](bit/remove_bit.py) +- [calculator : 計算機](calculator) + - [math_parser](calculator/math_parser.py) +- [dfs : 深さ優先探索](dfs) + - [all_factors](dfs/all_factors.py) + - [count_islands](dfs/count_islands.py) + - [pacific_atlantic](dfs/pacific_atlantic.py) + - [sudoku_solver](dfs/sudoku_solver.py) + - [walls_and_gates](dfs/walls_and_gates.py) +- [dp : 動的計画法](dp) + - [buy_sell_stock](dp/buy_sell_stock.py) + - [climbing_stairs](dp/climbing_stairs.py) + - [coin_change](dp/coin_change.py) + - [combination_sum](dp/combination_sum.py) + - [egg_drop](dp/egg_drop.py) + - [house_robber](dp/house_robber.py) + - [job_scheduling](dp/job_scheduling.py) + - [knapsack](dp/knapsack.py) + - [longest_increasing](dp/longest_increasing.py) + - [matrix_chain_order](dp/matrix_chain_order.py) + - [max_product_subarray](dp/max_product_subarray.py) + - [max_subarray](dp/max_subarray.py) + - [min_cost_path](dp/min_cost_path.py) + - [num_decodings](dp/num_decodings.py) + - [regex_matching](dp/regex_matching.py) + - [rod_cut](dp/rod_cut.py) + - [word_break](dp/word_break.py) + - [fibonacci](dp/fib.py) +- [graph : グラフ](graph) + - [strongly_connected](graph/checkDiGraphStronglyConnected.py) + - [clone_graph](graph/clone_graph.py) + - [cycle_detection](graph/cycle_detection.py) + - [find_all_cliques](graph/find_all_cliques.py) + - [find_path](graph/find_path.py) + - [graph](graph/graph.py) + - [markov_chain](graph/markov_chain.py) + - [minimum_spanning_tree](graph/minimum_spanning_tree.py) + - [satisfiability](graph/satisfiability.py) + - [tarjan](graph/tarjan.py) + - [traversal](graph/traversal.py) +- [heap : ヒープ](heap) + - [merge_sorted_k_lists](heap/merge_sorted_k_lists.py) + - [skyline](heap/skyline.py) + - [sliding_window_max](heap/sliding_window_max.py) + - [binary_heap](heap/binary_heap.py) +- [linkedlist : 連結リスト](linkedlist) + - [add_two_numbers](linkedlist/add_two_numbers.py) + - [copy_random_pointer](linkedlist/copy_random_pointer.py) + - [delete_node](linkedlist/delete_node.py) + - [first_cyclic_node](linkedlist/first_cyclic_node.py) + - [is_cyclic](linkedlist/is_cyclic.py) + - [is_palindrome](linkedlist/is_palindrome.py) + - [kth_to_last](linkedlist/kth_to_last.py) + - [linkedlist](linkedlist/linkedlist.py) + - [remove_duplicates](linkedlist/remove_duplicates.py) + - [reverse](linkedlist/reverse.py) + - [rotate_list](linkedlist/rotate_list.py) + - [swap_in_pairs](linkedlist/swap_in_pairs.py) + - [is_sorted](linkedlist/is_sorted.py) + - [remove_range](linkedlist/remove_range.py) +- [map : マップ](map) + - [hashtable](map/hashtable.py) + - [separate_chaining_hashtable](map/separate_chaining_hashtable.py) + - [longest_common_subsequence](map/longest_common_subsequence.py) + - [randomized_set](map/randomized_set.py) + - [valid_sudoku](map/valid_sudoku.py) +- [maths : 数学](maths) + - [base_conversion](maths/base_conversion.py) + - [extended_gcd](maths/extended_gcd.py) + - [gcd/lcm](maths/gcd.py) + - [generate_strobogrammtic](maths/generate_strobogrammtic.py) + - [is_strobogrammatic](maths/is_strobogrammatic.py) + - [next_bigger](maths/next_bigger.py) + - [next_perfect_square](maths/next_perfect_square.py) + - [nth_digit](maths/nth_digit.py) + - [prime_check](maths/prime_check.py) + - [primes_sieve_of_eratosthenes](maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](maths/pythagoras.py) + - [rabin_miller](maths/rabin_miller.py) + - [rsa](maths/rsa.py) + - [sqrt_precision_factor](maths/sqrt_precision_factor.py) + - [summing_digits](maths/summing_digits.py) +- [matrix : 行列](matrix) + - [sudoku_validator](matrix/sudoku_validator.py) + - [bomb_enemy](matrix/bomb_enemy.py) + - [copy_transform](matrix/copy_transform.py) + - [count_paths](matrix/count_paths.py) + - [matrix_rotation.txt](matrix/matrix_rotation.txt) + - [rotate_image](matrix/rotate_image.py) + - [search_in_sorted_matrix](matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](matrix/sparse_dot_vector.py) + - [sparse_mul](matrix/sparse_mul.py) + - [spiral_traversal](matrix/spiral_traversal.py) +- [queues : キュー](queues) + - [max_sliding_window](queues/max_sliding_window.py) + - [moving_average](queues/moving_average.py) + - [queue](queues/queue.py) + - [reconstruct_queue](queues/reconstruct_queue.py) + - [zigzagiterator](queues/zigzagiterator.py) +- [search : サーチ](search) + - [binary_search](search/binary_search.py) + - [first_occurance](search/first_occurance.py) + - [last_occurance](search/last_occurance.py) + - [search_insert](search/search_insert.py) + - [two_sum](search/two_sum.py) + - [search_range](search/search_range.py) + - [find_min_rotate](search/find_min_rotate.py) + - [search_rotate](search/search_rotate.py) +- [set : セット](set) + - [randomized_set](set/randomized_set.py) + - [set_covering](set/set_covering.py) +- [sort : ソート](sort) + - [bubble_sort](sort/bubble_sort.py) + - [comb_sort](sort/comb_sort.py) + - [counting_sort](sort/counting_sort.py) + - [heap_sort](sort/heap_sort.py) + - [insertion_sort](sort/insertion_sort.py) + - [meeting_rooms](sort/meeting_rooms.py) + - [merge_sort](sort/merge_sort.py) + - [quick_sort](sort/quick_sort.py) + - [selection_sort](sort/selection_sort.py) + - [sort_colors](sort/sort_colors.py) + - [topsort](sort/topsort.py) + - [wiggle_sort](sort/wiggle_sort.py) +- [stack : スタック](stack) + - [longest_abs_path](stack/longest_abs_path.py) + - [simplify_path](stack/simplify_path.py) + - [stack](stack/stack.py) + - [valid_parenthesis](stack/valid_parenthesis.py) + - [stutter](stack/stutter.py) + - [switch_pairs](stack/switch_pairs.py) + - [is_consecutive](stack/is_consecutive.py) + - [remove_min](stack/remove_min.py) + - [is_sorted](stack/is_sorted.py) +- [strings : 文字列](strings) + - [fizzbuzz](strings/fizzbuzz.py) + - [delete_reoccurring_characters](strings/delete_reoccurring_characters.py) + - [strip_url_params](strings/strip_url_params.py) + - [validate_coordinates](strings/validate_coordinates.py) + - [domain_extractor](strings/domain_extractor.py) + - [merge_string_checker](strings/merge_string_checker.py) + - [add_binary](strings/add_binary.py) + - [breaking_bad](strings/breaking_bad.py) + - [decode_string](strings/decode_string.py) + - [encode_decode](strings/encode_decode.py) + - [group_anagrams](strings/group_anagrams.py) + - [int_to_roman](strings/int_to_roman.py) + - [is_palindrome](strings/is_palindrome.py) + - [license_number](strings/license_number.py) + - [make_sentence](strings/make_sentence.py) + - [multiply_strings](strings/multiply_strings.py) + - [one_edit_distance](strings/one_edit_distance.py) + - [rabin_karp](strings/rabin_karp.py) + - [reverse_string](strings/reverse_string.py) + - [reverse_vowel](strings/reverse_vowel.py) + - [reverse_words](strings/reverse_words.py) + - [roman_to_int](strings/roman_to_int.py) + - [word_squares](strings/word_squares.py) +- [tree : 木構造](tree) + - [bst](tree/tree/bst) + - [array2bst](tree/bst/array2bst.py) + - [bst_closest_value](tree/bst/bst_closest_value.py) + - [BSTIterator](tree/bst/BSTIterator.py) + - [delete_node](tree/bst/delete_node.py) + - [is_bst](tree/bst/is_bst.py) + - [kth_smallest](tree/bst/kth_smallest.py) + - [lowest_common_ancestor](tree/bst/lowest_common_ancestor.py) + - [predecessor](tree/bst/predecessor.py) + - [serialize_deserialize](tree/bst/serialize_deserialize.py) + - [successor](tree/bst/successor.py) + - [unique_bst](tree/bst/unique_bst.py) + - [depth_sum](tree/bst/depth_sum.py) + - [count_left_node](tree/bst/count_left_node.py) + - [num_empty](tree/bst/num_empty.py) + - [height](tree/bst/height.py) + - [red_black_tree](tree/red_black_tree) + - [red_black_tree](tree/red_black_tree/red_black_tree.py) + - [segment_tree](tree/segment_tree) + - [segment_tree](tree/segment_tree/segment_tree.py) + - [traversal](tree/traversal) + - [inorder](tree/traversal/inorder.py) + - [level_order](tree/traversal/level_order.py) + - [zigzag](tree/traversal/zigzag.py) + - [trie](tree/trie) + - [add_and_search](tree/trie/add_and_search.py) + - [trie](tree/trie/trie.py) + - [binary_tree_paths](tree/binary_tree_paths.py) + - [bintree2list](tree/bintree2list.py) + - [deepest_left](tree/deepest_left.py) + - [invert_tree](tree/invert_tree.py) + - [is_balanced](tree/is_balanced.py) + - [is_subtree](tree/is_subtree.py) + - [is_symmetric](tree/is_symmetric.py) + - [longest_consecutive](tree/longest_consecutive.py) + - [lowest_common_ancestor](tree/lowest_common_ancestor.py) + - [max_height](tree/max_height.py) + - [max_path_sum](tree/max_path_sum.py) + - [min_height](tree/min_height.py) + - [path_sum](tree/path_sum.py) + - [path_sum2](tree/path_sum2.py) + - [pretty_print](tree/pretty_print.py) + - [same_tree](tree/same_tree.py) + - [tree](tree/tree.py) +- [union-find : 素集合データ構造](union-find) + - [count_islands](union-find/count_islands.py) + +## 貢献者 +本リポジトリは次の方によって維持されています + +* [Keon Kim](https://github.com/keon) +* [Rahul Goswami](https://github.com/goswami-rahul) +* [Christian Bender](https://github.com/christianbender) +* [Ankit Agarwal](https://github.com/ankit167) +* [Hai Hoang Dang](https://github.com/danghai) +* [Saad](https://github.com/SaadBenn) + +また、[全ての貢献者](https://github.com/keon/algorithms/graphs/contributors)に感謝を伝えます。 From a15d058ce3a1e71f11900e10cb54bb13f9aeab33 Mon Sep 17 00:00:00 2001 From: danghai Date: Thu, 31 May 2018 19:19:15 -0700 Subject: [PATCH 027/302] README.md: Update the link after reorganization --- README.md | 508 +++++++++++++++++++++++++++--------------------------- 1 file changed, 254 insertions(+), 254 deletions(-) diff --git a/README.md b/README.md index 1f518e63e..64195d352 100644 --- a/README.md +++ b/README.md @@ -52,260 +52,260 @@ If you want to uninstall algorithms, it is as simple as: ## List of Implementations -- [arrays](arrays) - - [delete_nth](arrays/delete_nth.py) - - [flatten](arrays/flatten.py) - - [garage](arrays/garage.py) - - [josephus_problem](arrays/josephus_problem.py) - - [longest_non_repeat](arrays/longest_non_repeat.py/) - - [merge_intervals](arrays/merge_intervals.py) - - [missing_ranges](arrays/missing_ranges.py) - - [plus_one](arrays/plus_one.py) -    - [rotate_array](arrays/rotate_array.py) - - [summary_ranges](arrays/summary_ranges.py) - - [three_sum](arrays/three_sum.py) - - [two_sum](arrays/two_sum.py) - - [move_zeros_to_end](arrays/move_zeros_to_end.py) -- [backtrack](backtrack) - - [general_solution.md](backtrack/) - - [anagram](backtrack/anagram.py) - - [array_sum_combinations](backtrack/array_sum_combinations.py) - - [combination_sum](backtrack/combination_sum.py) - - [expression_add_operators](backtrack/expression_add_operators.py) - - [factor_combinations](backtrack/factor_combinations.py) - - [generate_abbreviations](backtrack/generate_abbreviations.py) - - [generate_parenthesis](backtrack/generate_parenthesis.py) - - [letter_combination](backtrack/letter_combination.py) - - [palindrome_partitioning](backtrack/palindrome_partitioning.py) - - [pattern_match](backtrack/pattern_match.py) - - [permute](backtrack/permute.py) - - [permute_unique](backtrack/permute_unique.py) - - [subsets](backtrack/subsets.py) - - [subsets_unique](backtrack/subsets_unique.py) -- [bfs](bfs) - - [shortest_distance_from_all_buildings](bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](bfs/word_ladder.py) -- [bit](bit) - - [bytes_int_conversion](bit/bytes_int_conversion.py) - - [count_ones](bit/count_ones.py) - - [find_missing_number](bit/find_missing_number.py) - - [power_of_two](bit/power_of_two.py) - - [reverse_bits](bit/reverse_bits.py) - - [single_number](bit/single_number.py) - - [single_number2](bit/single_number2.py) - - [single_number3](bit/single_number3.py) - - [subsets](bit/subsets.py) - - [add_bitwise_operator](bit/add_bitwise_operator.py) - - [bit_operation](bit/bit_operation.py) - - [swap_pair](bit/swap_pair.py) - - [find_difference](bit/find_difference.py) - - [has_alternative_bit](bit/has_alternative_bit.py) - - [insert_bit](bit/insert_bit.py) - - [remove_bit](bit/remove_bit.py) -- [calculator](calculator) - - [math_parser](calculator/math_parser.py) -- [dfs](dfs) - - [all_factors](dfs/all_factors.py) - - [count_islands](dfs/count_islands.py) - - [pacific_atlantic](dfs/pacific_atlantic.py) - - [sudoku_solver](dfs/sudoku_solver.py) - - [walls_and_gates](dfs/walls_and_gates.py) -- [dp](dp) - - [buy_sell_stock](dp/buy_sell_stock.py) - - [climbing_stairs](dp/climbing_stairs.py) - - [coin_change](dp/coin_change.py) - - [combination_sum](dp/combination_sum.py) - - [egg_drop](dp/egg_drop.py) - - [house_robber](dp/house_robber.py) - - [job_scheduling](dp/job_scheduling.py) - - [knapsack](dp/knapsack.py) - - [longest_increasing](dp/longest_increasing.py) - - [matrix_chain_order](dp/matrix_chain_order.py) - - [max_product_subarray](dp/max_product_subarray.py) - - [max_subarray](dp/max_subarray.py) - - [min_cost_path](dp/min_cost_path.py) - - [num_decodings](dp/num_decodings.py) - - [regex_matching](dp/regex_matching.py) - - [rod_cut](dp/rod_cut.py) - - [word_break](dp/word_break.py) - - [fibonacci](dp/fib.py) -- [graph](graph) - - [strongly_connected](graph/checkDiGraphStronglyConnected.py) - - [clone_graph](graph/clone_graph.py) - - [cycle_detection](graph/cycle_detection.py) - - [find_all_cliques](graph/find_all_cliques.py) - - [find_path](graph/find_path.py) - - [graph](graph/graph.py) - - [markov_chain](graph/markov_chain.py) - - [minimum_spanning_tree](graph/minimum_spanning_tree.py) - - [satisfiability](graph/satisfiability.py) - - [tarjan](graph/tarjan.py) - - [traversal](graph/traversal.py) -- [heap](heap) - - [merge_sorted_k_lists](heap/merge_sorted_k_lists.py) - - [skyline](heap/skyline.py) - - [sliding_window_max](heap/sliding_window_max.py) - - [binary_heap](heap/binary_heap.py) -- [linkedlist](linkedlist) - - [add_two_numbers](linkedlist/add_two_numbers.py) - - [copy_random_pointer](linkedlist/copy_random_pointer.py) - - [delete_node](linkedlist/delete_node.py) - - [first_cyclic_node](linkedlist/first_cyclic_node.py) - - [is_cyclic](linkedlist/is_cyclic.py) - - [is_palindrome](linkedlist/is_palindrome.py) - - [kth_to_last](linkedlist/kth_to_last.py) - - [linkedlist](linkedlist/linkedlist.py) - - [remove_duplicates](linkedlist/remove_duplicates.py) - - [reverse](linkedlist/reverse.py) - - [rotate_list](linkedlist/rotate_list.py) - - [swap_in_pairs](linkedlist/swap_in_pairs.py) - - [is_sorted](linkedlist/is_sorted.py) - - [remove_range](linkedlist/remove_range.py) -- [map](map) - - [hashtable](map/hashtable.py) - - [separate_chaining_hashtable](map/separate_chaining_hashtable.py) - - [longest_common_subsequence](map/longest_common_subsequence.py) - - [randomized_set](map/randomized_set.py) - - [valid_sudoku](map/valid_sudoku.py) -- [maths](maths) - - [base_conversion](maths/base_conversion.py) - - [extended_gcd](maths/extended_gcd.py) - - [gcd/lcm](maths/gcd.py) - - [generate_strobogrammtic](maths/generate_strobogrammtic.py) - - [is_strobogrammatic](maths/is_strobogrammatic.py) - - [next_bigger](maths/next_bigger.py) - - [next_perfect_square](maths/next_perfect_square.py) - - [nth_digit](maths/nth_digit.py) - - [prime_check](maths/prime_check.py) - - [primes_sieve_of_eratosthenes](maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](maths/pythagoras.py) - - [rabin_miller](maths/rabin_miller.py) - - [rsa](maths/rsa.py) - - [sqrt_precision_factor](maths/sqrt_precision_factor.py) - - [summing_digits](maths/summing_digits.py) -- [matrix](matrix) - - [sudoku_validator](matrix/sudoku_validator.py) - - [bomb_enemy](matrix/bomb_enemy.py) - - [copy_transform](matrix/copy_transform.py) - - [count_paths](matrix/count_paths.py) - - [matrix_rotation.txt](matrix/matrix_rotation.txt) - - [rotate_image](matrix/rotate_image.py) - - [search_in_sorted_matrix](matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](matrix/sparse_dot_vector.py) - - [sparse_mul](matrix/sparse_mul.py) - - [spiral_traversal](matrix/spiral_traversal.py) -- [queues](queues) - - [max_sliding_window](queues/max_sliding_window.py) - - [moving_average](queues/moving_average.py) - - [queue](queues/queue.py) - - [reconstruct_queue](queues/reconstruct_queue.py) - - [zigzagiterator](queues/zigzagiterator.py) -- [search](search) - - [binary_search](search/binary_search.py) - - [first_occurance](search/first_occurance.py) - - [last_occurance](search/last_occurance.py) - - [search_insert](search/search_insert.py) - - [two_sum](search/two_sum.py) - - [search_range](search/search_range.py) - - [find_min_rotate](search/find_min_rotate.py) - - [search_rotate](search/search_rotate.py) -- [set](set) - - [randomized_set](set/randomized_set.py) - - [set_covering](set/set_covering.py) -- [sort](sort) - - [bubble_sort](sort/bubble_sort.py) - - [comb_sort](sort/comb_sort.py) - - [counting_sort](sort/counting_sort.py) - - [heap_sort](sort/heap_sort.py) - - [insertion_sort](sort/insertion_sort.py) - - [meeting_rooms](sort/meeting_rooms.py) - - [merge_sort](sort/merge_sort.py) - - [quick_sort](sort/quick_sort.py) - - [selection_sort](sort/selection_sort.py) - - [sort_colors](sort/sort_colors.py) - - [topsort](sort/topsort.py) - - [wiggle_sort](sort/wiggle_sort.py) -- [stack](stack) - - [longest_abs_path](stack/longest_abs_path.py) - - [simplify_path](stack/simplify_path.py) - - [stack](stack/stack.py) - - [valid_parenthesis](stack/valid_parenthesis.py) - - [stutter](stack/stutter.py) - - [switch_pairs](stack/switch_pairs.py) - - [is_consecutive](stack/is_consecutive.py) - - [remove_min](stack/remove_min.py) - - [is_sorted](stack/is_sorted.py) -- [strings](strings) - - [fizzbuzz](strings/fizzbuzz.py) - - [delete_reoccurring_characters](strings/delete_reoccurring_characters.py) - - [strip_url_params](strings/strip_url_params.py) - - [validate_coordinates](strings/validate_coordinates.py) - - [domain_extractor](strings/domain_extractor.py) - - [merge_string_checker](strings/merge_string_checker.py) - - [add_binary](strings/add_binary.py) - - [breaking_bad](strings/breaking_bad.py) - - [decode_string](strings/decode_string.py) - - [encode_decode](strings/encode_decode.py) - - [group_anagrams](strings/group_anagrams.py) - - [int_to_roman](strings/int_to_roman.py) - - [is_palindrome](strings/is_palindrome.py) - - [license_number](strings/license_number.py) - - [make_sentence](strings/make_sentence.py) - - [multiply_strings](strings/multiply_strings.py) - - [one_edit_distance](strings/one_edit_distance.py) - - [rabin_karp](strings/rabin_karp.py) - - [reverse_string](strings/reverse_string.py) - - [reverse_vowel](strings/reverse_vowel.py) - - [reverse_words](strings/reverse_words.py) - - [roman_to_int](strings/roman_to_int.py) - - [word_squares](strings/word_squares.py) -- [tree](tree) - - [bst](tree/tree/bst) - - [array2bst](tree/bst/array2bst.py) - - [bst_closest_value](tree/bst/bst_closest_value.py) - - [BSTIterator](tree/bst/BSTIterator.py) - - [delete_node](tree/bst/delete_node.py) - - [is_bst](tree/bst/is_bst.py) - - [kth_smallest](tree/bst/kth_smallest.py) - - [lowest_common_ancestor](tree/bst/lowest_common_ancestor.py) - - [predecessor](tree/bst/predecessor.py) - - [serialize_deserialize](tree/bst/serialize_deserialize.py) - - [successor](tree/bst/successor.py) - - [unique_bst](tree/bst/unique_bst.py) - - [depth_sum](tree/bst/depth_sum.py) - - [count_left_node](tree/bst/count_left_node.py) - - [num_empty](tree/bst/num_empty.py) - - [height](tree/bst/height.py) - - [red_black_tree](tree/red_black_tree) - - [red_black_tree](tree/red_black_tree/red_black_tree.py) - - [segment_tree](tree/segment_tree) - - [segment_tree](tree/segment_tree/segment_tree.py) - - [traversal](tree/traversal) - - [inorder](tree/traversal/inorder.py) - - [level_order](tree/traversal/level_order.py) - - [zigzag](tree/traversal/zigzag.py) - - [trie](tree/trie) - - [add_and_search](tree/trie/add_and_search.py) - - [trie](tree/trie/trie.py) - - [binary_tree_paths](tree/binary_tree_paths.py) - - [bintree2list](tree/bintree2list.py) - - [deepest_left](tree/deepest_left.py) - - [invert_tree](tree/invert_tree.py) - - [is_balanced](tree/is_balanced.py) - - [is_subtree](tree/is_subtree.py) - - [is_symmetric](tree/is_symmetric.py) - - [longest_consecutive](tree/longest_consecutive.py) - - [lowest_common_ancestor](tree/lowest_common_ancestor.py) - - [max_height](tree/max_height.py) - - [max_path_sum](tree/max_path_sum.py) - - [min_height](tree/min_height.py) - - [path_sum](tree/path_sum.py) - - [path_sum2](tree/path_sum2.py) - - [pretty_print](tree/pretty_print.py) - - [same_tree](tree/same_tree.py) - - [tree](tree/tree.py) -- [union-find](union-find) - - [count_islands](union-find/count_islands.py) +- [arrays](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) +    - [rotate_array](algorithms/arrays/rotate_array.py) + - [summary_ranges](algorithms/arrays/summary_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) +- [backtrack](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs](algorithms/bfs) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit](algorithms/bit) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [find_difference](algorithms/bit/find_difference.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) +- [calculator](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph](algorithms/graph) + - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) +- [maths](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurance](algorithms/search/first_occurance.py) + - [last_occurance](algorithms/search/last_occurance.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) +- [set](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) +- [sort](algorithms/sort) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [topsort](algorithms/sort/topsort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) +- [tree](algorithms/tree) + - [bst](algorithms/tree/tree/bst) + - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bintree2list](algorithms/tree/bintree2list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [union-find](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) ## Contributors The repo is maintained by From 59138dc3eebfd5e3c0fb9e550100e385e2a42830 Mon Sep 17 00:00:00 2001 From: danghai Date: Thu, 31 May 2018 19:34:35 -0700 Subject: [PATCH 028/302] README_CN.md: Update the link after reorganization --- README_CN.md | 419 +++++++++++++++++++++++++-------------------------- 1 file changed, 209 insertions(+), 210 deletions(-) diff --git a/README_CN.md b/README_CN.md index c612cd522..af502aa2f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -42,16 +42,16 @@ pip3 install git+https://github.com/keon/algorithms ``` -通过创建python文件(比如:在sort模块使用merge_sort)进行测试: +通过创建python文件(比如:在sort模块使用merge_sort)进行测试: ``` -from sort import merge_sort +from algorithms.sort import merge_sort if __name__ == "__main__": my_list = [1, 8, 3, 5, 6] - my_list = merge_sort.merge_sort(my_list) + my_list = merge_sort(my_list) print(my_list) - + ``` ## 卸载 @@ -66,212 +66,212 @@ pip3 uninstall -y algorithms ## 实现列表 - [array:数组](arrays) - - [delete_nth: 删除第n项](arrays/delete_nth.py) - - [flatten:数组降维](arrays/flatten.py) - - [garage:停车场](arrays/garage.py) - - [josephus_problem: 约瑟夫问题](arrays/josephus_problem.py) - - [longest_non_repeat:最长不重复子串](arrays/longest_non_repeat.py/) - - [merge_intervals:合并重叠间隔](arrays/merge_intervals.py) - - [missing_ranges:遗失的范围](arrays/missing_ranges.py) - - [plus_one:加一运算](arrays/plus_one.py) - - [rotate_array:反转数组](arrays/rotate_array.py) - - [summary_ranges:数组范围](arrays/summary_ranges.py) - - [three_sum:三数和为零](arrays/three_sum.py) - - [two_sum:两数和](arrays/two_sum.py) - - [move_zeros_to_end: 0后置问题](arrays/move_zeros_to_end.py) -- [backtrack:回溯](backtrack) - - [general_solution.md:一般方法](backtrack/) - - [anagram:同字母异序词](backtrack/anagram.py) - - [array_sum_combinations:数组和](backtrack/array_sum_combinations.py) - - [combination_sum:和的合并](backtrack/combination_sum.py) - - [expression_add_operators:给表达式添加运算符](backtrack/expression_add_operators.py) - - [factor_combinations:因素组合](backtrack/factor_combinations.py) - - [generate_abbreviations:缩写生成](backtrack/generate_abbreviations.py) - - [generate_parenthesis:括号生成](backtrack/generate_parenthesis.py) - - [letter_combination:字母组合](backtrack/letter_combination.py) - - [palindrome_partitioning:字符串的所有回文子串](backtrack/palindrome_partitioning.py) - - [pattern_match:模式匹配](backtrack/pattern_match.py) - - [permute:排列](backtrack/permute.py) - - [permute_unique:唯一排列](backtrack/permute_unique.py) - - [subsets:子集](backtrack/subsets.py) - - [subsets_unique:唯一子集](backtrack/subsets_unique.py) -- [bfs:广度优先搜索](bfs) - - [shortest_distance_from_all_buildings:所有建筑物的最短路径:](bfs/shortest_distance_from_all_buildings.py) - - [word_ladder:词语阶梯](bfs/word_ladder.py) -- [bit:位操作](bit) - - [bytes_int_conversion:字节整数转换](bit/bytes_int_conversion.py) - - [count_ones:统计1出现的次数](bit/count_ones.py) - - [find_missing_number:寻找缺失数](bit/find_missing_number.py) - - [power_of_two:2的n次方数判断](bit/power_of_two.py) - - [reverse_bits:反转位](bit/reverse_bits.py) - - [single_number2:寻找出现1次的数(2)](bit/single_number2.py) - - [single_number:寻找出现1次的数(1)](bit/single_number.py) - - [subsets: 求所有子集](bit/subsets.py) - - [add_bitwise_operator:无操作符的加法](bit/add_bitwise_operator.py) -- [calculator:计算](calculator) - - [math_parser: 数字解析](calculator/math_parser.py) -- [dfs:深度优先搜索](dfs) - - [all_factors:因素分解](dfs/all_factors.py) - - [count_islands:岛计数](dfs/count_islands.py) - - [pacific_atlantic:太平洋大西洋](dfs/pacific_atlantic.py) - - [sudoku_solver:数独解法](dfs/sudoku_solver.py) - - [walls_and_gates:墙和门](dfs/walls_and_gates.py) -- [dp:动态规划](dp) - - [buy_sell_stock:股票买卖](dp/buy_sell_stock.py) - - [climbing_stairs:爬梯子问题](dp/climbing_stairs.py) - - [combination_sum:和组合问题](dp/combination_sum.py) - - [house_robber:打家劫舍](dp/house_robber.py) - - [knapsack:背包问题](dp/knapsack.py) - - [longest_increasing:最长递增子序列](dp/longest_increasing.py) - - [max_product_subarray:最大子数组乘积](dp/max_product_subarray.py) - - [max_subarray:最大子数组](dp/max_subarray.py) - - [num_decodings:数字解码](dp/num_decodings.py) - - [regex_matching:正则匹配](dp/regex_matching.py) - - [word_break:单词分割](dp/word_break.py) + - [delete_nth: 删除第n项](algorithms/arrays/delete_nth.py) + - [flatten:数组降维](algorithms/arrays/flatten.py) + - [garage:停车场](algorithms/arrays/garage.py) + - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus_problem.py) + - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) + - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) + - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) + - [plus_one:加一运算](algorithms/arrays/plus_one.py) + - [rotate_array:反转数组](algorithms/arrays/rotate_array.py) + - [summary_ranges:数组范围](algorithms/arrays/summary_ranges.py) + - [three_sum:三数和为零](algorithms/arrays/three_sum.py) + - [two_sum:两数和](algorithms/arrays/two_sum.py) + - [move_zeros_to_end: 0后置问题](algorithms/arrays/move_zeros_to_end.py) +- [backtrack:回溯](algorithms/backtrack) + - [general_solution.md:一般方法](algorithms/backtrack/) + - [anagram:同字母异序词](algorithms/backtrack/anagram.py) + - [array_sum_combinations:数组和](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum:和的合并](algorithms/backtrack/combination_sum.py) + - [expression_add_operators:给表达式添加运算符](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations:因素组合](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations:缩写生成](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis:括号生成](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination:字母组合](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning:字符串的所有回文子串](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match:模式匹配](algorithms/backtrack/pattern_match.py) + - [permute:排列](algorithms/backtrack/permute.py) + - [permute_unique:唯一排列](algorithms/backtrack/permute_unique.py) + - [subsets:子集](algorithms/backtrack/subsets.py) + - [subsets_unique:唯一子集](algorithms/backtrack/subsets_unique.py) +- [bfs:广度优先搜索](algorithms/bfs) + - [shortest_distance_from_all_buildings:所有建筑物的最短路径:](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder:词语阶梯](algorithms/bfs/word_ladder.py) +- [bit:位操作](algorithms/bit) + - [bytes_int_conversion:字节整数转换](algorithms/bit/bytes_int_conversion.py) + - [count_ones:统计1出现的次数](algorithms/bit/count_ones.py) + - [find_missing_number:寻找缺失数](algorithms/bit/find_missing_number.py) + - [power_of_two:2的n次方数判断](algorithms/bit/power_of_two.py) + - [reverse_bits:反转位](algorithms/bit/reverse_bits.py) + - [single_number2:寻找出现1次的数(2)](algorithms/bit/single_number2.py) + - [single_number:寻找出现1次的数(1)](algorithms/bit/single_number.py) + - [subsets: 求所有子集](algorithms/bit/subsets.py) + - [add_bitwise_operator:无操作符的加法](algorithms/bit/add_bitwise_operator.py) +- [calculator:计算](algorithms/calculator) + - [math_parser: 数字解析](algorithms/calculator/math_parser.py) +- [dfs:深度优先搜索](algorithms/dfs) + - [all_factors:因素分解](algorithms/dfs/all_factors.py) + - [count_islands:岛计数](algorithms/dfs/count_islands.py) + - [pacific_atlantic:太平洋大西洋](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver:数独解法](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates:墙和门](algorithms/dfs/walls_and_gates.py) +- [dp:动态规划](algorithms/dp) + - [buy_sell_stock:股票买卖](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs:爬梯子问题](algorithms/dp/climbing_stairs.py) + - [combination_sum:和组合问题](algorithms/dp/combination_sum.py) + - [house_robber:打家劫舍](algorithms/dp/house_robber.py) + - [knapsack:背包问题](algorithms/dp/knapsack.py) + - [longest_increasing:最长递增子序列](algorithms/dp/longest_increasing.py) + - [max_product_subarray:最大子数组乘积](algorithms/dp/max_product_subarray.py) + - [max_subarray:最大子数组](algorithms/dp/max_subarray.py) + - [num_decodings:数字解码](algorithms/dp/num_decodings.py) + - [regex_matching:正则匹配](algorithms/dp/regex_matching.py) + - [word_break:单词分割](algorithms/dp/word_break.py) - [graph:图](graph) - - [2-sat:2-sat](graph/satisfiability.py) - - [clone_graph:克隆图](graph/clone_graph.py) - - [cycle_detection:判断圈算法](graph/cycle_detection.py) - - [find_path:发现路径](graph/find_path.py) - - [graph:图](graph/graph.py) - - [traversal:遍历](graph/traversal.py) - - [markov_chain:马尔可夫链](graph/markov_chain.py) -- [heap:堆](heap) - - [merge_sorted_k_lists:合并k个有序链](heap/merge_sorted_k_lists.py) - - [skyline:天际线](heap/skyline.py) - - [sliding_window_max:滑动窗口最大值](heap/sliding_window_max.py) -- [linkedlist:链表](linkedlist) - - [add_two_numbers:链表数相加](linkedlist/add_two_numbers.py) - - [copy_random_pointer:复制带有随机指针的链表](linkedlist/copy_random_pointer.py) - - [delete_node:删除节点](linkedlist/delete_node.py) - - [first_cyclic_node:环链表的第一个节点](linkedlist/first_cyclic_node.py) - - [is_cyclic:判断环链表](linkedlist/is_cyclic.py) - - [is_palindrome:回文链表](linkedlist/is_palindrome.py) - - [kth_to_last:倒数第k个节点](linkedlist/kth_to_last.py) - - [linkedlist: 链表](linkedlist/linkedlist.py) - - [remove_duplicates:删除重复元素](linkedlist/remove_duplicates.py) - - [reverse:反转链表](linkedlist/reverse.py) - - [rotate_list:旋转链表](linkedlist/rotate_list.py) - - [swap_in_pairs:链表节点交换](linkedlist/swap_in_pairs.py) -- [map:映射](map) - - [hashtable:哈希表](map/hashtable.py) - - [separate_chaining_hashtable:拉链法哈希表](map/separate_chaining_hashtable.py) - - [longest_common_subsequence:最长公共子序列](map/longest_common_subsequence.py) - - [randomized_set:随机集](map/randomized_set.py) - - [valid_sudoku:有效数独](map/valid_sudoku.py) -- [math:数学问题](maths) - - [extended_gcd:扩展欧几里得算法](maths/extended_gcd.py) - - [gcd/lcm:最大公约数和最小公倍数](maths/gcd.py) - - [prime_test:主要测试](maths/prime_test.py) - - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](maths/primes_sieve_of_eratosthenes.py) - - [generate_strobogrammtic:生成对称数](maths/generate_strobogrammtic.py) - - [is_strobogrammatic:判断对称数](maths/is_strobogrammatic.py) - - [nth_digit:第n位](maths/nth_digit.py) - - [rabin_miller:米勒-拉宾素性检验](maths/rabin_miller.py) - - [rsa:rsa加密](maths/rsa.py) - - [sqrt_precision_factor:开发精度因素](maths/sqrt_precision_factor.py) - - [pythagoras:毕达哥拉斯](maths/pythagoras.py) -- [matrix:矩阵](matrix) - - [matrix_rotation:矩阵旋转](matrix/matrix_rotation.txt) - - [copy_transform:复制变换](matrix/copy_transform.py) - - [bomb_enemy:炸弹人](matrix/bomb_enemy.py) - - [rotate_image:旋转图像](matrix/rotate_image.py) - - [sparse_dot_vector:解析点向量](matrix/sparse_dot_vector.py) - - [sparse_mul:稀疏矩阵](matrix/sparse_mul.py) - - [spiral_traversal:循环遍历](matrix/spiral_traversal.py) - - [count_paths:计算路径](matrix/count_paths.py) -- [queue:队列](queues) - - [max_sliding_window:最大移动窗口](queues/max_sliding_window.py) - - [moving_average:移动平均](queues/moving_average.py) - - [queue:队列](queues/queue.py) - - [reconstruct_queue:重建队列](queues/reconstruct_queue.py) - - [zigzagiterator:锯齿形迭代](queues/zigzagiterator.py) -- [search:查找](search) - - [binary_search:二分查找](search/binary_search.py) - - [count_elem:元素计数](search/count_elem.py) - - [first_occurance:首次出现](search/first_occurance.py) - - [last_occurance:最后一次出现](search/last_occurance.py) -- [set:集合](set) - - [randomized_set:随机集合](set/randomized_set.py) - - [set_covering:集合覆盖](set/set_covering.py) -- [sort:排序](sort) - - [bubble_sort:冒泡排序](sort/bubble_sort.py) - - [comb_sort:梳排序](sort/comb_sort.py) - - [counting_sort:计数排序](sort/counting_sort.py) - - [heap_sort:堆排序](sort/heap_sort.py) - - [insertion_sort:插入排序](sort/insertion_sort.py) - - [meeting_rooms:会议室](sort/meeting_rooms.py) - - [merge_sort:归并排序](sort/merge_sort.py) - - [quick_sort:快速排序](sort/quick_sort.py) - - [selection_sort:选择排序](sort/selection_sort.py) - - [sort_colors:颜色排序](sort/sort_colors.py) - - [topsort:top排序](sort/topsort.py) - - [wiggle_sort:摇摆排序](sort/wiggle_sort.py) -- [stack:栈](stack) - - [longest_abs_path:最长相对路径](stack/longest_abs_path.py) - - [simplify_path:简化路径](stack/simplify_path.py) - - [stack:栈](stack/stack.py) - - [valid_parenthesis:验证括号](stack/valid_parenthesis.py) -- [string:字符串](strings) - - [add_binary:二进制数相加](strings/add_binary.py) - - [breaking_bad:打破坏](strings/breaking_bad.py) - - [decode_string:字符串编码](strings/decode_string.py) - - [encode_decode:编解码](strings/encode_decode.py) - - [group_anagrams:群组错位词](strings/group_anagrams.py) - - [int_to_roman:整数转换罗马数字](strings/int_to_roman.py) - - [is_palindrome:回文字符串](strings/is_palindrome.py) - - [license_number:拍照号码](strings/license_number.py) - - [make_sentence:造句](strings/make_sentence.py) - - [multiply_strings:字符串相乘](strings/multiply_strings.py) - - [one_edit_distance:一个编辑距离](strings/one_edit_distance.py) - - [rabin_karp:Rabin-Karp 算法](strings/rabin_karp.py) - - [reverse_string:反转字符串](strings/reverse_string.py) - - [reverse_vowel:反转元音](strings/reverse_vowel.py) - - [reverse_words:反转单词](strings/reverse_words.py) - - [roman_to_int:罗马数转换整数](strings/roman_to_int.py) - - [word_squares:单词平方](strings/word_squares.py) -- [tree:树](tree) - - [segment-tree:线段树](tree/segment_tree) - - [segment_tree:线段树](tree/segment_tree/segment_tree.py) - - [binary_tree_paths:二叉树路径](tree/binary_tree_paths.py) - - [bintree2list:二叉树转换链表](tree/bintree2list.py) - - [bst:二叉搜索树](tree/tree/bst) - - [array2bst:数组转换](tree/bst/array2bst.py) - - [bst_closest_value:最近二叉搜索树值](tree/bst/bst_closest_value.py) - - [BSTIterator:二叉搜索树迭代](tree/bst/BSTIterator.py) - - [delete_node:删除节点](tree/bst/delete_node.py) - - [is_bst:判断二叉搜索树](tree/bst/is_bst.py) - - [kth_smallest:二叉搜索树的第k小节点](tree/bst/kth_smallest.py) - - [lowest_common_ancestor:最近公共祖先](tree/bst/lowest_common_ancestor.py) - - [predecessor:前任](tree/bst/predecessor.py) - - [serialize_deserialize:序列化反序列化](tree/bst/serialize_deserialize.py) - - [successor:继承者](tree/bst/successor.py) - - [unique_bst:唯一BST](tree/bst/unique_bst.py) - - [deepest_left:最深叶子节点](tree/deepest_left.py) - - [invert_tree:反转树](tree/invert_tree.py) - - [is_balanced:判断平衡树](tree/is_balanced.py) - - [is_subtree:判断子树](tree/is_subtree.py) - - [is_symmetric:判断对称树](tree/is_symmetric.py) - - [longest_consecutive:最长连续节点](tree/longest_consecutive.py) - - [lowest_common_ancestor:最近公共祖先](tree/lowest_common_ancestor.py) - - [max_height:最大高度](tree/max_height.py) - - [max_path_sum:最长路径和](tree/max_path_sum.py) - - [min_height:最小高度](tree/min_height.py) - - [path_sum2:路径和2](tree/path_sum2.py) - - [path_sum:路径和](tree/path_sum.py) - - [pretty_print:完美打印](tree/pretty_print.py) - - [same_tree:相同树](tree/same_tree.py) - - [traversal:遍历](tree/traversal) - - [inorder:中序遍历](tree/traversal/inorder.py) - - [level_order:层次遍历](tree/traversal/level_order.py) - - [zigzag:锯齿形遍历](tree/traversal/zigzag.py) - - [tree:树](tree/tree.py) - - [trie:字典树](tree/trie) - - [add_and_search:添加和查找](tree/trie/add_and_search.py) - - [trie:字典](tree/trie/trie.py) -- [union-find:并查集](union-find) - - [count_islands:岛计数](union-find/count_islands.py) - + - [2-sat:2-sat](algorithms/graph/satisfiability.py) + - [clone_graph:克隆图](algorithms/graph/clone_graph.py) + - [cycle_detection:判断圈算法](algorithms/graph/cycle_detection.py) + - [find_path:发现路径](algorithms/graph/find_path.py) + - [graph:图](algorithms/graph/graph.py) + - [traversal:遍历](algorithms/graph/traversal.py) + - [markov_chain:马尔可夫链](algorithms/graph/markov_chain.py) +- [heap:堆](algorithms/heap) + - [merge_sorted_k_lists:合并k个有序链](algorithms/heap/merge_sorted_k_lists.py) + - [skyline:天际线](algorithms/heap/skyline.py) + - [sliding_window_max:滑动窗口最大值](algorithms/heap/sliding_window_max.py) +- [linkedlist:链表](algorithms/linkedlist) + - [add_two_numbers:链表数相加](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer:复制带有随机指针的链表](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node:删除节点](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node:环链表的第一个节点](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic:判断环链表](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome:回文链表](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last:倒数第k个节点](algorithms/linkedlist/kth_to_last.py) + - [linkedlist: 链表](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates:删除重复元素](algorithms/linkedlist/remove_duplicates.py) + - [reverse:反转链表](algorithms/linkedlist/reverse.py) + - [rotate_list:旋转链表](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs:链表节点交换](algorithms/linkedlist/swap_in_pairs.py) +- [map:映射](algorithms/map) + - [hashtable:哈希表](algorithms/map/hashtable.py) + - [separate_chaining_hashtable:拉链法哈希表](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence:最长公共子序列](algorithms/map/longest_common_subsequence.py) + - [randomized_set:随机集](algorithms/map/randomized_set.py) + - [valid_sudoku:有效数独](algorithms/map/valid_sudoku.py) +- [math:数学问题](algorithms/maths) + - [extended_gcd:扩展欧几里得算法](algorithms/maths/extended_gcd.py) + - [gcd/lcm:最大公约数和最小公倍数](algorithms/maths/gcd.py) + - [prime_test:主要测试](algorithms/maths/prime_test.py) + - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [generate_strobogrammtic:生成对称数](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic:判断对称数](algorithms/maths/is_strobogrammatic.py) + - [nth_digit:第n位](algorithms/maths/nth_digit.py) + - [rabin_miller:米勒-拉宾素性检验](algorithms/maths/rabin_miller.py) + - [rsa:rsa加密](algorithms/maths/rsa.py) + - [sqrt_precision_factor:开发精度因素](algorithms/maths/sqrt_precision_factor.py) + - [pythagoras:毕达哥拉斯](algorithms/maths/pythagoras.py) +- [matrix:矩阵](algorithms/matrix) + - [matrix_rotation:矩阵旋转](algorithms/matrix/matrix_rotation.txt) + - [copy_transform:复制变换](algorithms/matrix/copy_transform.py) + - [bomb_enemy:炸弹人](algorithms/matrix/bomb_enemy.py) + - [rotate_image:旋转图像](algorithms/matrix/rotate_image.py) + - [sparse_dot_vector:解析点向量](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul:稀疏矩阵](algorithms/matrix/sparse_mul.py) + - [spiral_traversal:循环遍历](algorithms/matrix/spiral_traversal.py) + - [count_paths:计算路径](algorithms/matrix/count_paths.py) +- [queue:队列](algorithms/queues) + - [max_sliding_window:最大移动窗口](algorithms/queues/max_sliding_window.py) + - [moving_average:移动平均](algorithms/queues/moving_average.py) + - [queue:队列](algorithms/queues/queue.py) + - [reconstruct_queue:重建队列](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator:锯齿形迭代](algorithms/queues/zigzagiterator.py) +- [search:查找](algorithms/search) + - [binary_search:二分查找](algorithms/search/binary_search.py) + - [count_elem:元素计数](algorithms/search/count_elem.py) + - [first_occurance:首次出现](algorithms/search/first_occurance.py) + - [last_occurance:最后一次出现](algorithms/search/last_occurance.py) +- [set:集合](algorithms/set) + - [randomized_set:随机集合](algorithms/set/randomized_set.py) + - [set_covering:集合覆盖](algorithms/set/set_covering.py) +- [sort:排序](algorithms/sort) + - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) + - [comb_sort:梳排序](algorithms/sort/comb_sort.py) + - [counting_sort:计数排序](algorithms/sort/counting_sort.py) + - [heap_sort:堆排序](algorithms/sort/heap_sort.py) + - [insertion_sort:插入排序](algorithms/sort/insertion_sort.py) + - [meeting_rooms:会议室](algorithms/sort/meeting_rooms.py) + - [merge_sort:归并排序](algorithms/sort/merge_sort.py) + - [quick_sort:快速排序](algorithms/sort/quick_sort.py) + - [selection_sort:选择排序](algorithms/sort/selection_sort.py) + - [sort_colors:颜色排序](algorithms/sort/sort_colors.py) + - [topsort:top排序](algorithms/sort/topsort.py) + - [wiggle_sort:摇摆排序](algorithms/sort/wiggle_sort.py) +- [stack:栈](algorithms/stack) + - [longest_abs_path:最长相对路径](algorithms/stack/longest_abs_path.py) + - [simplify_path:简化路径](algorithms/stack/simplify_path.py) + - [stack:栈](algorithms/stack/stack.py) + - [valid_parenthesis:验证括号](algorithms/stack/valid_parenthesis.py) +- [string:字符串](algorithms/strings) + - [add_binary:二进制数相加](algorithms/strings/add_binary.py) + - [breaking_bad:打破坏](algorithms/strings/breaking_bad.py) + - [decode_string:字符串编码](algorithms/strings/decode_string.py) + - [encode_decode:编解码](algorithms/strings/encode_decode.py) + - [group_anagrams:群组错位词](algorithms/strings/group_anagrams.py) + - [int_to_roman:整数转换罗马数字](algorithms/strings/int_to_roman.py) + - [is_palindrome:回文字符串](algorithms/strings/is_palindrome.py) + - [license_number:拍照号码](algorithms/strings/license_number.py) + - [make_sentence:造句](algorithms/strings/make_sentence.py) + - [multiply_strings:字符串相乘](algorithms/strings/multiply_strings.py) + - [one_edit_distance:一个编辑距离](algorithms/strings/one_edit_distance.py) + - [rabin_karp:Rabin-Karp 算法](algorithms/strings/rabin_karp.py) + - [reverse_string:反转字符串](algorithms/strings/reverse_string.py) + - [reverse_vowel:反转元音](algorithms/strings/reverse_vowel.py) + - [reverse_words:反转单词](algorithms/strings/reverse_words.py) + - [roman_to_int:罗马数转换整数](algorithms/strings/roman_to_int.py) + - [word_squares:单词平方](algorithms/strings/word_squares.py) +- [tree:树](algorithms/tree) + - [segment-tree:线段树](algorithms/tree/segment_tree) + - [segment_tree:线段树](algorithms/tree/segment_tree/segment_tree.py) + - [binary_tree_paths:二叉树路径](algorithms/tree/binary_tree_paths.py) + - [bintree2list:二叉树转换链表](algorithms/tree/bintree2list.py) + - [bst:二叉搜索树](algorithms/tree/tree/bst) + - [array2bst:数组转换](algorithms/tree/bst/array2bst.py) + - [bst_closest_value:最近二叉搜索树值](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator:二叉搜索树迭代](algorithms/tree/bst/BSTIterator.py) + - [delete_node:删除节点](algorithms/tree/bst/delete_node.py) + - [is_bst:判断二叉搜索树](algorithms/tree/bst/is_bst.py) + - [kth_smallest:二叉搜索树的第k小节点](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor:最近公共祖先](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor:前任](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize:序列化反序列化](algorithms/tree/bst/serialize_deserialize.py) + - [successor:继承者](algorithms/tree/bst/successor.py) + - [unique_bst:唯一BST](algorithms/tree/bst/unique_bst.py) + - [deepest_left:最深叶子节点](algorithms/tree/deepest_left.py) + - [invert_tree:反转树](algorithms/tree/invert_tree.py) + - [is_balanced:判断平衡树](algorithms/tree/is_balanced.py) + - [is_subtree:判断子树](algorithms/tree/is_subtree.py) + - [is_symmetric:判断对称树](algorithms/tree/is_symmetric.py) + - [longest_consecutive:最长连续节点](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor:最近公共祖先](algorithms/tree/lowest_common_ancestor.py) + - [max_height:最大高度](algorithms/tree/max_height.py) + - [max_path_sum:最长路径和](algorithms/tree/max_path_sum.py) + - [min_height:最小高度](algorithms/tree/min_height.py) + - [path_sum2:路径和2](algorithms/tree/path_sum2.py) + - [path_sum:路径和](algorithms/tree/path_sum.py) + - [pretty_print:完美打印](algorithms/tree/pretty_print.py) + - [same_tree:相同树](algorithms/tree/same_tree.py) + - [traversal:遍历](algorithms/tree/traversal) + - [inorder:中序遍历](algorithms/tree/traversal/inorder.py) + - [level_order:层次遍历](algorithms/tree/traversal/level_order.py) + - [zigzag:锯齿形遍历](algorithms/tree/traversal/zigzag.py) + - [tree:树](algorithms/tree/tree.py) + - [trie:字典树](algorithms/tree/trie) + - [add_and_search:添加和查找](algorithms/tree/trie/add_and_search.py) + - [trie:字典](algorithms/tree/trie/trie.py) +- [union-find:并查集](algorithms/union-find) + - [count_islands:岛计数](algorithms/union-find/count_islands.py) + ## 贡献 谢谢主要维护人员: @@ -284,4 +284,3 @@ pip3 uninstall -y algorithms * [Saad](https://github.com/SaadBenn) 以及[所有贡献者](https://github.com/keon/algorithms/graphs/contributors) - From 711f9781407ed33ccc928e00a4a2670c7317657b Mon Sep 17 00:00:00 2001 From: danghai Date: Thu, 31 May 2018 19:40:36 -0700 Subject: [PATCH 029/302] README_GE.md: Update the link after reorganization --- README_GE.md | 512 +++++++++++++++++++++++++-------------------------- 1 file changed, 256 insertions(+), 256 deletions(-) diff --git a/README_GE.md b/README_GE.md index af1b8b2c4..8258aae29 100644 --- a/README_GE.md +++ b/README_GE.md @@ -42,11 +42,11 @@ Wenn Sie das Projekt installieren wollen, um es als Module in Ihren Projekten nu Sie können die Installation testen in dem Sie unten stehenden Code in eine Datei packen und ausführen. ```python3 -from sort import merge_sort +from algorithms.sort import merge_sort if __name__ == "__main__": my_list = [1, 8, 3, 5, 6] - my_list = merge_sort.merge_sort(my_list) + my_list = merge_sort(my_list) print(my_list) ``` @@ -59,260 +59,260 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: ## Liste von Implementierungen -- [arrays](arrays) - - [delete_nth](arrays/delete_nth.py) - - [flatten](arrays/flatten.py) - - [garage](arrays/garage.py) - - [josephus_problem](arrays/josephus_problem.py) - - [longest_non_repeat](arrays/longest_non_repeat.py/) - - [merge_intervals](arrays/merge_intervals.py) - - [missing_ranges](arrays/missing_ranges.py) - - [plus_one](arrays/plus_one.py) -    - [rotate_array](arrays/rotate_array.py) - - [summary_ranges](arrays/summary_ranges.py) - - [three_sum](arrays/three_sum.py) - - [two_sum](arrays/two_sum.py) - - [move_zeros_to_end](arrays/move_zeros_to_end.py) -- [backtrack](backtrack) - - [general_solution.md](backtrack/) - - [anagram](backtrack/anagram.py) - - [array_sum_combinations](backtrack/array_sum_combinations.py) - - [combination_sum](backtrack/combination_sum.py) - - [expression_add_operators](backtrack/expression_add_operators.py) - - [factor_combinations](backtrack/factor_combinations.py) - - [generate_abbreviations](backtrack/generate_abbreviations.py) - - [generate_parenthesis](backtrack/generate_parenthesis.py) - - [letter_combination](backtrack/letter_combination.py) - - [palindrome_partitioning](backtrack/palindrome_partitioning.py) - - [pattern_match](backtrack/pattern_match.py) - - [permute](backtrack/permute.py) - - [permute_unique](backtrack/permute_unique.py) - - [subsets](backtrack/subsets.py) - - [subsets_unique](backtrack/subsets_unique.py) -- [bfs](bfs) - - [shortest_distance_from_all_buildings](bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](bfs/word_ladder.py) -- [bit](bit) - - [bytes_int_conversion](bit/bytes_int_conversion.py) - - [count_ones](bit/count_ones.py) - - [find_missing_number](bit/find_missing_number.py) - - [power_of_two](bit/power_of_two.py) - - [reverse_bits](bit/reverse_bits.py) - - [single_number](bit/single_number.py) - - [single_number2](bit/single_number2.py) - - [single_number3](bit/single_number3.py) - - [subsets](bit/subsets.py) - - [add_bitwise_operator](bit/add_bitwise_operator.py) - - [bit_operation](bit/bit_operation.py) - - [swap_pair](bit/swap_pair.py) - - [find_difference](bit/find_difference.py) - - [has_alternative_bit](bit/has_alternative_bit.py) - - [insert_bit](bit/insert_bit.py) - - [remove_bit](bit/remove_bit.py) -- [calculator](calculator) - - [math_parser](calculator/math_parser.py) -- [dfs](dfs) - - [all_factors](dfs/all_factors.py) - - [count_islands](dfs/count_islands.py) - - [pacific_atlantic](dfs/pacific_atlantic.py) - - [sudoku_solver](dfs/sudoku_solver.py) - - [walls_and_gates](dfs/walls_and_gates.py) -- [dp](dp) - - [buy_sell_stock](dp/buy_sell_stock.py) - - [climbing_stairs](dp/climbing_stairs.py) - - [coin_change](dp/coin_change.py) - - [combination_sum](dp/combination_sum.py) - - [egg_drop](dp/egg_drop.py) - - [house_robber](dp/house_robber.py) - - [job_scheduling](dp/job_scheduling.py) - - [knapsack](dp/knapsack.py) - - [longest_increasing](dp/longest_increasing.py) - - [matrix_chain_order](dp/matrix_chain_order.py) - - [max_product_subarray](dp/max_product_subarray.py) - - [max_subarray](dp/max_subarray.py) - - [min_cost_path](dp/min_cost_path.py) - - [num_decodings](dp/num_decodings.py) - - [regex_matching](dp/regex_matching.py) - - [rod_cut](dp/rod_cut.py) - - [word_break](dp/word_break.py) - - [fibonacci](dp/fib.py) -- [graph](graph) - - [strongly_connected](graph/checkDiGraphStronglyConnected.py) - - [clone_graph](graph/clone_graph.py) - - [cycle_detection](graph/cycle_detection.py) - - [find_all_cliques](graph/find_all_cliques.py) - - [find_path](graph/find_path.py) - - [graph](graph/graph.py) - - [markov_chain](graph/markov_chain.py) - - [minimum_spanning_tree](graph/minimum_spanning_tree.py) - - [satisfiability](graph/satisfiability.py) - - [tarjan](graph/tarjan.py) - - [traversal](graph/traversal.py) -- [heap](heap) - - [merge_sorted_k_lists](heap/merge_sorted_k_lists.py) - - [skyline](heap/skyline.py) - - [sliding_window_max](heap/sliding_window_max.py) - - [binary_heap](heap/binary_heap.py) -- [linkedlist](linkedlist) - - [add_two_numbers](linkedlist/add_two_numbers.py) - - [copy_random_pointer](linkedlist/copy_random_pointer.py) - - [delete_node](linkedlist/delete_node.py) - - [first_cyclic_node](linkedlist/first_cyclic_node.py) - - [is_cyclic](linkedlist/is_cyclic.py) - - [is_palindrome](linkedlist/is_palindrome.py) - - [kth_to_last](linkedlist/kth_to_last.py) - - [linkedlist](linkedlist/linkedlist.py) - - [remove_duplicates](linkedlist/remove_duplicates.py) - - [reverse](linkedlist/reverse.py) - - [rotate_list](linkedlist/rotate_list.py) - - [swap_in_pairs](linkedlist/swap_in_pairs.py) - - [is_sorted](linkedlist/is_sorted.py) - - [remove_range](linkedlist/remove_range.py) -- [map](map) - - [hashtable](map/hashtable.py) - - [separate_chaining_hashtable](map/separate_chaining_hashtable.py) - - [longest_common_subsequence](map/longest_common_subsequence.py) - - [randomized_set](map/randomized_set.py) - - [valid_sudoku](map/valid_sudoku.py) -- [maths](maths) - - [base_conversion](maths/base_conversion.py) - - [extended_gcd](maths/extended_gcd.py) - - [gcd/lcm](maths/gcd.py) - - [generate_strobogrammtic](maths/generate_strobogrammtic.py) - - [is_strobogrammatic](maths/is_strobogrammatic.py) - - [next_bigger](maths/next_bigger.py) - - [next_perfect_square](maths/next_perfect_square.py) - - [nth_digit](maths/nth_digit.py) - - [prime_check](maths/prime_check.py) - - [primes_sieve_of_eratosthenes](maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](maths/pythagoras.py) - - [rabin_miller](maths/rabin_miller.py) - - [rsa](maths/rsa.py) - - [sqrt_precision_factor](maths/sqrt_precision_factor.py) - - [summing_digits](maths/summing_digits.py) -- [matrix](matrix) - - [sudoku_validator](matrix/sudoku_validator.py) - - [bomb_enemy](matrix/bomb_enemy.py) - - [copy_transform](matrix/copy_transform.py) - - [count_paths](matrix/count_paths.py) - - [matrix_rotation.txt](matrix/matrix_rotation.txt) - - [rotate_image](matrix/rotate_image.py) - - [search_in_sorted_matrix](matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](matrix/sparse_dot_vector.py) - - [sparse_mul](matrix/sparse_mul.py) - - [spiral_traversal](matrix/spiral_traversal.py) -- [queues](queues) - - [max_sliding_window](queues/max_sliding_window.py) - - [moving_average](queues/moving_average.py) - - [queue](queues/queue.py) - - [reconstruct_queue](queues/reconstruct_queue.py) - - [zigzagiterator](queues/zigzagiterator.py) -- [search](search) - - [binary_search](search/binary_search.py) - - [first_occurance](search/first_occurance.py) - - [last_occurance](search/last_occurance.py) - - [search_insert](search/search_insert.py) - - [two_sum](search/two_sum.py) - - [search_range](search/search_range.py) - - [find_min_rotate](search/find_min_rotate.py) - - [search_rotate](search/search_rotate.py) -- [set](set) - - [randomized_set](set/randomized_set.py) - - [set_covering](set/set_covering.py) -- [sort](sort) - - [bubble_sort](sort/bubble_sort.py) - - [comb_sort](sort/comb_sort.py) - - [counting_sort](sort/counting_sort.py) - - [heap_sort](sort/heap_sort.py) - - [insertion_sort](sort/insertion_sort.py) - - [meeting_rooms](sort/meeting_rooms.py) - - [merge_sort](sort/merge_sort.py) - - [quick_sort](sort/quick_sort.py) - - [selection_sort](sort/selection_sort.py) - - [sort_colors](sort/sort_colors.py) - - [topsort](sort/topsort.py) - - [wiggle_sort](sort/wiggle_sort.py) -- [stack](stack) - - [longest_abs_path](stack/longest_abs_path.py) - - [simplify_path](stack/simplify_path.py) - - [stack](stack/stack.py) - - [valid_parenthesis](stack/valid_parenthesis.py) - - [stutter](stack/stutter.py) - - [switch_pairs](stack/switch_pairs.py) - - [is_consecutive](stack/is_consecutive.py) - - [remove_min](stack/remove_min.py) - - [is_sorted](stack/is_sorted.py) -- [strings](strings) - - [fizzbuzz](strings/fizzbuzz.py) - - [delete_reoccurring_characters](strings/delete_reoccurring_characters.py) - - [strip_url_params](strings/strip_url_params.py) - - [validate_coordinates](strings/validate_coordinates.py) - - [domain_extractor](strings/domain_extractor.py) - - [merge_string_checker](strings/merge_string_checker.py) - - [add_binary](strings/add_binary.py) - - [breaking_bad](strings/breaking_bad.py) - - [decode_string](strings/decode_string.py) - - [encode_decode](strings/encode_decode.py) - - [group_anagrams](strings/group_anagrams.py) - - [int_to_roman](strings/int_to_roman.py) - - [is_palindrome](strings/is_palindrome.py) - - [license_number](strings/license_number.py) - - [make_sentence](strings/make_sentence.py) - - [multiply_strings](strings/multiply_strings.py) - - [one_edit_distance](strings/one_edit_distance.py) - - [rabin_karp](strings/rabin_karp.py) - - [reverse_string](strings/reverse_string.py) - - [reverse_vowel](strings/reverse_vowel.py) - - [reverse_words](strings/reverse_words.py) - - [roman_to_int](strings/roman_to_int.py) - - [word_squares](strings/word_squares.py) -- [tree](tree) - - [bst](tree/tree/bst) - - [array2bst](tree/bst/array2bst.py) - - [bst_closest_value](tree/bst/bst_closest_value.py) - - [BSTIterator](tree/bst/BSTIterator.py) - - [delete_node](tree/bst/delete_node.py) - - [is_bst](tree/bst/is_bst.py) - - [kth_smallest](tree/bst/kth_smallest.py) - - [lowest_common_ancestor](tree/bst/lowest_common_ancestor.py) - - [predecessor](tree/bst/predecessor.py) - - [serialize_deserialize](tree/bst/serialize_deserialize.py) - - [successor](tree/bst/successor.py) - - [unique_bst](tree/bst/unique_bst.py) - - [depth_sum](tree/bst/depth_sum.py) - - [count_left_node](tree/bst/count_left_node.py) - - [num_empty](tree/bst/num_empty.py) - - [height](tree/bst/height.py) - - [red_black_tree](tree/red_black_tree) - - [red_black_tree](tree/red_black_tree/red_black_tree.py) - - [segment_tree](tree/segment_tree) - - [segment_tree](tree/segment_tree/segment_tree.py) - - [traversal](tree/traversal) - - [inorder](tree/traversal/inorder.py) - - [level_order](tree/traversal/level_order.py) - - [zigzag](tree/traversal/zigzag.py) - - [trie](tree/trie) - - [add_and_search](tree/trie/add_and_search.py) - - [trie](tree/trie/trie.py) - - [binary_tree_paths](tree/binary_tree_paths.py) - - [bintree2list](tree/bintree2list.py) - - [deepest_left](tree/deepest_left.py) - - [invert_tree](tree/invert_tree.py) - - [is_balanced](tree/is_balanced.py) - - [is_subtree](tree/is_subtree.py) - - [is_symmetric](tree/is_symmetric.py) - - [longest_consecutive](tree/longest_consecutive.py) - - [lowest_common_ancestor](tree/lowest_common_ancestor.py) - - [max_height](tree/max_height.py) - - [max_path_sum](tree/max_path_sum.py) - - [min_height](tree/min_height.py) - - [path_sum](tree/path_sum.py) - - [path_sum2](tree/path_sum2.py) - - [pretty_print](tree/pretty_print.py) - - [same_tree](tree/same_tree.py) - - [tree](tree/tree.py) -- [union-find](union-find) - - [count_islands](union-find/count_islands.py) +- [arrays](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) +    - [rotate_array](algorithms/arrays/rotate_array.py) + - [summary_ranges](algorithms/arrays/summary_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) +- [backtrack](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs](algorithms/bfs) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit](algorithms/bit) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [find_difference](algorithms/bit/find_difference.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) +- [calculator](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph](algorithms/graph) + - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) +- [maths](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurance](algorithms/search/first_occurance.py) + - [last_occurance](algorithms/search/last_occurance.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) +- [set](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) +- [sort](algorithms/sort) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [topsort](algorithms/sort/topsort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) +- [tree](algorithms/tree) + - [bst](algorithms/tree/tree/bst) + - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bintree2list](algorithms/tree/bintree2list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [union-find](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) ## Mitwirkende From b39f4e52d06dc64706a8f9eec3adb5e5744a573b Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Sat, 2 Jun 2018 05:59:31 +0900 Subject: [PATCH 030/302] added bucket_sort.py & shell_sort.py (#296) * Create bucket_sort.py * Create shell_sort.py * Update test_sort.py * Update __init__.py --- algorithms/sort/__init__.py | 2 ++ algorithms/sort/bucket_sort.py | 28 ++++++++++++++++++++++++++++ algorithms/sort/shell_sort.py | 21 +++++++++++++++++++++ tests/test_sort.py | 13 ++++++++++++- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 algorithms/sort/bucket_sort.py create mode 100644 algorithms/sort/shell_sort.py diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index 20a3cf326..665a0d70d 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -6,3 +6,5 @@ from .merge_sort import * from .quick_sort import * from .selection_sort import * +from .bucket_sort import * +from .shell_sort import * diff --git a/algorithms/sort/bucket_sort.py b/algorithms/sort/bucket_sort.py new file mode 100644 index 000000000..d89232ccf --- /dev/null +++ b/algorithms/sort/bucket_sort.py @@ -0,0 +1,28 @@ +def bucket_sort(arr): + ''' Bucket Sort + Complexity: O(n^2) + The complexity is dominated by nextSort + ''' + # The number of buckets and make buckets + num_buckets = len(arr) + buckets = [[] for bucket in range(num_buckets)] + # Assign values into bucket_sort + for value in arr: + index = value * num_buckets // (max(arr) + 1) + buckets[index].append(value) + # Sort + sorted_list = [] + for i in range(num_buckets): + sorted_list.extend(next_sort(buckets[i])) + return sorted_list + +def next_sort(arr): + # We will use insertion sort here. + for i in range(1, len(arr)): + j = i - 1 + key = arr[i] + while arr[j] > key and j >= 0: + arr[j+1] = arr[j] + j = j - 1 + arr[j + 1] = key + return arr diff --git a/algorithms/sort/shell_sort.py b/algorithms/sort/shell_sort.py new file mode 100644 index 000000000..61f5f612e --- /dev/null +++ b/algorithms/sort/shell_sort.py @@ -0,0 +1,21 @@ +def shell_sort(arr): + ''' Shell Sort + Complexity: O(n^2) + ''' + n = len(arr) + # Initialize size of the gap + gap = n//2 + + while gap > 0: + y_index = gap + while y_index < len(arr): + y = arr[y_index] + x_index = y_index - gap + while x_index >= 0 and y < arr[x_index]: + arr[x_index + gap] = arr[x_index] + x_index = x_index - gap + arr[x_index + gap] = y + y_index = y_index + 1 + gap = gap//2 + + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index 07d13c8f3..43d5bf29e 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -6,7 +6,9 @@ insertion_sort, merge_sort, quick_sort, - selection_sort + selection_sort, + bucket_sort, + shell_sort ) import unittest @@ -49,6 +51,15 @@ def test_selection_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], selection_sort([1, 5, 65, 23, 57, 1232])) + def test_bucket_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + bucket_sort([1, 5, 65, 23, 57, 1232])) + + def test_shell_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + shell_sort([1, 5, 65, 23, 57, 1232])) + + if __name__ == "__main__": unittest.main() From b905623fd950be879d8940b3892b016407378f8c Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Sat, 2 Jun 2018 07:47:29 +0530 Subject: [PATCH 031/302] add some bit problems (#294) * add arrays/max_ones_index * add 2 algorithms to algorithms/bit * update all READMEs --- README.md | 11 ++++-- README_CN.md | 7 +++- README_GE.md | 5 ++- README_JP.md | 3 ++ algorithms/arrays/__init__.py | 1 + algorithms/arrays/max_ones_index.py | 43 +++++++++++++++++++++ algorithms/bit/__init__.py | 2 + algorithms/bit/count_flips_to_convert.py | 19 +++++++++ algorithms/bit/flip_bit_longest_sequence.py | 30 ++++++++++++++ tests/test_array.py | 38 +++++++++++------- tests/test_bit.py | 30 ++++++++++++-- 11 files changed, 166 insertions(+), 23 deletions(-) create mode 100644 algorithms/arrays/max_ones_index.py create mode 100644 algorithms/bit/count_flips_to_convert.py create mode 100644 algorithms/bit/flip_bit_longest_sequence.py diff --git a/README.md b/README.md index f67925c52..83547b14a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -English | [简体中文](https://github.com/yunshuipiao/algorithms/blob/master/README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) +English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) @@ -58,6 +58,7 @@ If you want to uninstall algorithms, it is as simple as: - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus_problem.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) @@ -86,19 +87,21 @@ If you want to uninstall algorithms, it is as simple as: - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder](algorithms/bfs/word_ladder.py) - [bit](algorithms/bit) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - [count_ones](algorithms/bit/count_ones.py) + - [find_difference](algorithms/bit/find_difference.py) - [find_missing_number](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - [power_of_two](algorithms/bit/power_of_two.py) - [reverse_bits](algorithms/bit/reverse_bits.py) - [single_number](algorithms/bit/single_number.py) - [single_number2](algorithms/bit/single_number2.py) - [single_number3](algorithms/bit/single_number3.py) - [subsets](algorithms/bit/subsets.py) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - [swap_pair](algorithms/bit/swap_pair.py) - - [find_difference](algorithms/bit/find_difference.py) - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - [insert_bit](algorithms/bit/insert_bit.py) - [remove_bit](algorithms/bit/remove_bit.py) diff --git a/README_CN.md b/README_CN.md index bd0f31391..cccfd5dfc 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -[English](https://github.com/yunshuipiao/algorithms/blob/master/README.md) | 简体中文 | [日本語](README_JP.md) +[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) Python版数据结构和算法 ========================================= @@ -70,7 +70,8 @@ pip3 uninstall -y algorithms - [flatten:数组降维](algorithms/arrays/flatten.py) - [garage:停车场](algorithms/arrays/garage.py) - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus_problem.py) - - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) + - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) - [plus_one:加一运算](algorithms/arrays/plus_one.py) @@ -101,7 +102,9 @@ pip3 uninstall -y algorithms - [bit:位操作](algorithms/bit) - [bytes_int_conversion:字节整数转换](algorithms/bit/bytes_int_conversion.py) - [count_ones:统计1出现的次数](algorithms/bit/count_ones.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - [find_missing_number:寻找缺失数](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - [power_of_two:2的n次方数判断](algorithms/bit/power_of_two.py) - [reverse_bits:反转位](algorithms/bit/reverse_bits.py) - [single_number2:寻找出现1次的数(2)](algorithms/bit/single_number2.py) diff --git a/README_GE.md b/README_GE.md index 3c14f99f2..d4287c35b 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](https://github.com/yunshuipiao/algorithms/blob/master/README_CN.md) | Deutsch | [日本語](README_JP.md) +[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) @@ -65,6 +65,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus_problem.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) @@ -95,7 +96,9 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [bit](algorithms/bit) - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - [count_ones](algorithms/bit/count_ones.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - [find_missing_number](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - [power_of_two](algorithms/bit/power_of_two.py) - [reverse_bits](algorithms/bit/reverse_bits.py) - [single_number](algorithms/bit/single_number.py) diff --git a/README_JP.md b/README_JP.md index 352d728fe..316a82cb9 100644 --- a/README_JP.md +++ b/README_JP.md @@ -54,6 +54,7 @@ if __name__ == "__main__": - [flatten](arrays/flatten.py) - [garage](arrays/garage.py) - [josephus_problem](arrays/josephus_problem.py) + - [max_ones_index](algorithms/arrays/max_ones_index.py) - [longest_non_repeat](arrays/longest_non_repeat.py/) - [merge_intervals](arrays/merge_intervals.py) - [missing_ranges](arrays/missing_ranges.py) @@ -85,7 +86,9 @@ if __name__ == "__main__": - [bit : ビット](bit) - [bytes_int_conversion](bit/bytes_int_conversion.py) - [count_ones](bit/count_ones.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - [find_missing_number](bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - [power_of_two](bit/power_of_two.py) - [reverse_bits](bit/reverse_bits.py) - [single_number](bit/single_number.py) diff --git a/algorithms/arrays/__init__.py b/algorithms/arrays/__init__.py index 04afdb2f9..64ba13065 100644 --- a/algorithms/arrays/__init__.py +++ b/algorithms/arrays/__init__.py @@ -3,6 +3,7 @@ from .garage import * from .josephus import * from .longest_non_repeat import * +from .max_ones_index import * from .merge_intervals import * from .missing_ranges import * from .move_zeros import * diff --git a/algorithms/arrays/max_ones_index.py b/algorithms/arrays/max_ones_index.py new file mode 100644 index 000000000..bee1f760d --- /dev/null +++ b/algorithms/arrays/max_ones_index.py @@ -0,0 +1,43 @@ +""" +Find the index of 0 to be replaced with 1 to get +longest continuous sequence +of 1s in a binary array. +Returns index of 0 to be +replaced with 1 to get longest +continuous sequence of 1s. +If there is no 0 in array, then +it returns -1. + +e.g. +let input array = [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1] +If we replace 0 at index 3 with 1, we get the longest continuous +sequence of 1s in the array. +So the function return => 3 +""" + + +def max_ones_index(arr): + + n = len(arr) + max_count = 0 + max_index = 0 + prev_zero = -1 + prev_prev_zero = -1 + + for curr in range(n): + + # If current element is 0, + # then calculate the difference + # between curr and prev_prev_zero + if arr[curr] == 0: + if curr - prev_prev_zero > max_count: + max_count = curr - prev_prev_zero + max_index = prev_zero + + prev_prev_zero = prev_zero + prev_zero = curr + + if n - prev_prev_zero > max_count: + max_index = prev_zero + + return max_index \ No newline at end of file diff --git a/algorithms/bit/__init__.py b/algorithms/bit/__init__.py index 7cd175f6a..383923d46 100644 --- a/algorithms/bit/__init__.py +++ b/algorithms/bit/__init__.py @@ -13,3 +13,5 @@ from .has_alternative_bit import * from .insert_bit import * from .remove_bit import * +from .count_flips_to_convert import * +from .flip_bit_longest_sequence import * diff --git a/algorithms/bit/count_flips_to_convert.py b/algorithms/bit/count_flips_to_convert.py new file mode 100644 index 000000000..6ba1d116d --- /dev/null +++ b/algorithms/bit/count_flips_to_convert.py @@ -0,0 +1,19 @@ +""" +Write a function to determine the number of bits you would need to +flip to convert integer A to integer B. +For example: +Input: 29 (or: 11101), 15 (or: 01111) +Output: 2 +""" + + +def count_flips_to_convert(a, b): + + diff = a ^ b + + # count number of ones in diff + count = 0 + while diff: + diff &= (diff - 1) + count += 1 + return count diff --git a/algorithms/bit/flip_bit_longest_sequence.py b/algorithms/bit/flip_bit_longest_sequence.py new file mode 100644 index 000000000..a952edb3e --- /dev/null +++ b/algorithms/bit/flip_bit_longest_sequence.py @@ -0,0 +1,30 @@ +""" +You have an integer and you can flip exactly one bit from a 0 to 1. +Write code to find the length of the longest sequence of 1s you could create. +For example: +Input: 1775 ( or: 11011101111) +Output: 8 +""" + + +def flip_bit_longest_seq(num): + + curr_len = 0 + prev_len = 0 + max_len = 0 + + while num: + if num & 1 == 1: # last digit is 1 + curr_len += 1 + + elif num & 1 == 0: # last digit is 0 + if num & 2 == 0: # second last digit is 0 + prev_len = 0 + else: + prev_len = curr_len + curr_len = 0 + + max_len = max(max_len, prev_len + curr_len) + num = num >> 1 # right shift num + + return max_len + 1 diff --git a/tests/test_array.py b/tests/test_array.py index 88cf59173..ed398bca7 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -1,16 +1,19 @@ -from algorithms.arrays import delete_nth, delete_nth_naive -from algorithms.arrays import flatten, flatten_iter -from algorithms.arrays import garage -from algorithms.arrays import josephus -from algorithms.arrays import longest_non_repeat_v1, longest_non_repeat_v2 -from algorithms.arrays import Interval, merge_intervals -from algorithms.arrays import missing_ranges -from algorithms.arrays import move_zeros -from algorithms.arrays import plus_one_v1, plus_one_v2, plus_one_v3 -from algorithms.arrays import rotate_v1, rotate_v2, rotate_v3 -from algorithms.arrays import summarize_ranges -from algorithms.arrays import three_sum -from algorithms.arrays import two_sum +from algorithms.arrays import ( + delete_nth, delete_nth_naive, + flatten_iter, flatten, + garage, + josephus, + longest_non_repeat_v1, longest_non_repeat_v2, + Interval, merge_intervals, + missing_ranges, + move_zeros, + plus_one_v1, plus_one_v2, plus_one_v3, + rotate_v1, rotate_v2, rotate_v3, + summarize_ranges, + three_sum, + two_sum, + max_ones_index +) import unittest @@ -152,6 +155,15 @@ def test_longest_non_repeat_v2(self): self.assertEqual(longest_non_repeat_v2(string), 3) +class TestMaxOnesIndex(unittest.TestCase): + + def test_max_ones_index(self): + + self.assertEqual(9, max_ones_index([1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1])) + self.assertEqual(3, max_ones_index([1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1])) + self.assertEqual(-1, max_ones_index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])) + + class TestMergeInterval(unittest.TestCase): def test_merge(self): diff --git a/tests/test_bit.py b/tests/test_bit.py index 01290c2f3..fdc80a18e 100644 --- a/tests/test_bit.py +++ b/tests/test_bit.py @@ -1,7 +1,9 @@ from algorithms.bit import ( add_bitwise_operator, count_ones_iter, count_ones_recur, + count_flips_to_convert, find_missing_number, find_missing_number2, + flip_bit_longest_seq, is_power_of_two, reverse_bits, single_number, @@ -19,8 +21,13 @@ import unittest import random + class TestSuite(unittest.TestCase): + def setUp(self): + """Initialize seed.""" + random.seed("test") + def test_add_bitwise_operator(self): self.assertEqual(5432 + 97823, add_bitwise_operator(5432, 97823)) self.assertEqual(0, add_bitwise_operator(0, 0)) @@ -55,9 +62,15 @@ def test_count_ones_iter(self): # 0 -> 0 self.assertEqual(0, count_ones_iter(0)) - def setUp(self): - """Initialize seed.""" - random.seed("test") + def test_count_flips_to_convert(self): + # 29: 11101 and 15: 01111 + self.assertEqual(2, count_flips_to_convert(29, 15)) + # 45: 0000101101 and 987: 1111011011 + self.assertEqual(8, count_flips_to_convert(45, 987)) + # 34: 100010 + self.assertEqual(0, count_flips_to_convert(34, 34)) + # 34: 100010 and 53: 110101 + self.assertEqual(4, count_flips_to_convert(34, 53)) def test_find_missing_number(self): @@ -79,6 +92,16 @@ def test_find_missing_number2(self): random.shuffle(nums) self.assertEqual(12345, find_missing_number2(nums)) + def test_flip_bit_longest_seq(self): + # 1775: 11011101111 + self.assertEqual(8, flip_bit_longest_seq(1775)) + # 5: 101 + self.assertEqual(3, flip_bit_longest_seq(5)) + # 71: 1000111 + self.assertEqual(4, flip_bit_longest_seq(71)) + # 0: 0 + self.assertEqual(1, flip_bit_longest_seq(0)) + def test_is_power_of_two(self): self.assertTrue(is_power_of_two(64)) @@ -215,5 +238,6 @@ def test_remove_bit(self): self.assertEqual(5, remove_bit(21, 4)) self.assertEqual(10, remove_bit(21, 0)) + if __name__ == '__main__': unittest.main() From 942c027097be7b65b747cfd5efd92bab5c01048a Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Sat, 2 Jun 2018 18:09:15 +0900 Subject: [PATCH 032/302] Update README for bucket and shell sort (#298) * Update README.md * Update README_JP.md * Update README_JP.md * Update README_GE.md * Update README_CN.md --- README.md | 2 + README_CN.md | 2 + README_GE.md | 2 + README_JP.md | 510 ++++++++++++++++++++++++++------------------------- 4 files changed, 262 insertions(+), 254 deletions(-) diff --git a/README.md b/README.md index 83547b14a..b33ca6002 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,7 @@ If you want to uninstall algorithms, it is as simple as: - [set_covering](algorithms/set/set_covering.py) - [sort](algorithms/sort) - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) @@ -225,6 +226,7 @@ If you want to uninstall algorithms, it is as simple as: - [merge_sort](algorithms/sort/merge_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - [topsort](algorithms/sort/topsort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) diff --git a/README_CN.md b/README_CN.md index cccfd5dfc..166414b84 100644 --- a/README_CN.md +++ b/README_CN.md @@ -199,6 +199,7 @@ pip3 uninstall -y algorithms - [set_covering:集合覆盖](algorithms/set/set_covering.py) - [sort:排序](algorithms/sort) - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort:梳排序](algorithms/sort/comb_sort.py) - [counting_sort:计数排序](algorithms/sort/counting_sort.py) - [heap_sort:堆排序](algorithms/sort/heap_sort.py) @@ -207,6 +208,7 @@ pip3 uninstall -y algorithms - [merge_sort:归并排序](algorithms/sort/merge_sort.py) - [quick_sort:快速排序](algorithms/sort/quick_sort.py) - [selection_sort:选择排序](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors:颜色排序](algorithms/sort/sort_colors.py) - [topsort:top排序](algorithms/sort/topsort.py) - [wiggle_sort:摇摆排序](algorithms/sort/wiggle_sort.py) diff --git a/README_GE.md b/README_GE.md index d4287c35b..02cfdb906 100644 --- a/README_GE.md +++ b/README_GE.md @@ -224,6 +224,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [set_covering](algorithms/set/set_covering.py) - [sort](algorithms/sort) - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) @@ -232,6 +233,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [merge_sort](algorithms/sort/merge_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - [topsort](algorithms/sort/topsort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) diff --git a/README_JP.md b/README_JP.md index 316a82cb9..4804b5fc5 100644 --- a/README_JP.md +++ b/README_JP.md @@ -49,263 +49,265 @@ if __name__ == "__main__": ## アルゴリズムのリスト -- [arrays : 配列](arrays) - - [delete_nth](arrays/delete_nth.py) - - [flatten](arrays/flatten.py) - - [garage](arrays/garage.py) - - [josephus_problem](arrays/josephus_problem.py) +- [arrays : 配列](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus_problem.py) - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [longest_non_repeat](arrays/longest_non_repeat.py/) - - [merge_intervals](arrays/merge_intervals.py) - - [missing_ranges](arrays/missing_ranges.py) - - [plus_one](arrays/plus_one.py) - - [rotate_array](arrays/rotate_array.py) - - [summary_ranges](arrays/summary_ranges.py) - - [three_sum](arrays/three_sum.py) - - [two_sum](arrays/two_sum.py) - - [move_zeros_to_end](arrays/move_zeros_to_end.py) -- [backtrack : バックトラッキング](backtrack) - - [general_solution.md](backtrack/) - - [anagram](backtrack/anagram.py) - - [array_sum_combinations](backtrack/array_sum_combinations.py) - - [combination_sum](backtrack/combination_sum.py) - - [expression_add_operators](backtrack/expression_add_operators.py) - - [factor_combinations](backtrack/factor_combinations.py) - - [generate_abbreviations](backtrack/generate_abbreviations.py) - - [generate_parenthesis](backtrack/generate_parenthesis.py) - - [letter_combination](backtrack/letter_combination.py) - - [palindrome_partitioning](backtrack/palindrome_partitioning.py) - - [pattern_match](backtrack/pattern_match.py) - - [permute](backtrack/permute.py) - - [permute_unique](backtrack/permute_unique.py) - - [subsets](backtrack/subsets.py) - - [subsets_unique](backtrack/subsets_unique.py) -- [bfs : 幅優先探索](bfs) - - [shortest_distance_from_all_buildings](bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](bfs/word_ladder.py) -- [bit : ビット](bit) - - [bytes_int_conversion](bit/bytes_int_conversion.py) - - [count_ones](bit/count_ones.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) + - [rotate_array](algorithms/arrays/rotate_array.py) + - [summary_ranges](algorithms/arrays/summary_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) +- [backtrack : バックトラッキング](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs : 幅優先探索](algorithms/bfs) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit : ビット](algorithms/bit) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_ones](algorithms/bit/count_ones.py) - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [find_missing_number](bit/find_missing_number.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](bit/power_of_two.py) - - [reverse_bits](bit/reverse_bits.py) - - [single_number](bit/single_number.py) - - [single_number2](bit/single_number2.py) - - [single_number3](bit/single_number3.py) - - [subsets](bit/subsets.py) - - [add_bitwise_operator](bit/add_bitwise_operator.py) - - [bit_operation](bit/bit_operation.py) - - [swap_pair](bit/swap_pair.py) - - [find_difference](bit/find_difference.py) - - [has_alternative_bit](bit/has_alternative_bit.py) - - [insert_bit](bit/insert_bit.py) - - [remove_bit](bit/remove_bit.py) -- [calculator : 計算機](calculator) - - [math_parser](calculator/math_parser.py) -- [dfs : 深さ優先探索](dfs) - - [all_factors](dfs/all_factors.py) - - [count_islands](dfs/count_islands.py) - - [pacific_atlantic](dfs/pacific_atlantic.py) - - [sudoku_solver](dfs/sudoku_solver.py) - - [walls_and_gates](dfs/walls_and_gates.py) -- [dp : 動的計画法](dp) - - [buy_sell_stock](dp/buy_sell_stock.py) - - [climbing_stairs](dp/climbing_stairs.py) - - [coin_change](dp/coin_change.py) - - [combination_sum](dp/combination_sum.py) - - [egg_drop](dp/egg_drop.py) - - [house_robber](dp/house_robber.py) - - [job_scheduling](dp/job_scheduling.py) - - [knapsack](dp/knapsack.py) - - [longest_increasing](dp/longest_increasing.py) - - [matrix_chain_order](dp/matrix_chain_order.py) - - [max_product_subarray](dp/max_product_subarray.py) - - [max_subarray](dp/max_subarray.py) - - [min_cost_path](dp/min_cost_path.py) - - [num_decodings](dp/num_decodings.py) - - [regex_matching](dp/regex_matching.py) - - [rod_cut](dp/rod_cut.py) - - [word_break](dp/word_break.py) - - [fibonacci](dp/fib.py) -- [graph : グラフ](graph) - - [strongly_connected](graph/checkDiGraphStronglyConnected.py) - - [clone_graph](graph/clone_graph.py) - - [cycle_detection](graph/cycle_detection.py) - - [find_all_cliques](graph/find_all_cliques.py) - - [find_path](graph/find_path.py) - - [graph](graph/graph.py) - - [markov_chain](graph/markov_chain.py) - - [minimum_spanning_tree](graph/minimum_spanning_tree.py) - - [satisfiability](graph/satisfiability.py) - - [tarjan](graph/tarjan.py) - - [traversal](graph/traversal.py) -- [heap : ヒープ](heap) - - [merge_sorted_k_lists](heap/merge_sorted_k_lists.py) - - [skyline](heap/skyline.py) - - [sliding_window_max](heap/sliding_window_max.py) - - [binary_heap](heap/binary_heap.py) -- [linkedlist : 連結リスト](linkedlist) - - [add_two_numbers](linkedlist/add_two_numbers.py) - - [copy_random_pointer](linkedlist/copy_random_pointer.py) - - [delete_node](linkedlist/delete_node.py) - - [first_cyclic_node](linkedlist/first_cyclic_node.py) - - [is_cyclic](linkedlist/is_cyclic.py) - - [is_palindrome](linkedlist/is_palindrome.py) - - [kth_to_last](linkedlist/kth_to_last.py) - - [linkedlist](linkedlist/linkedlist.py) - - [remove_duplicates](linkedlist/remove_duplicates.py) - - [reverse](linkedlist/reverse.py) - - [rotate_list](linkedlist/rotate_list.py) - - [swap_in_pairs](linkedlist/swap_in_pairs.py) - - [is_sorted](linkedlist/is_sorted.py) - - [remove_range](linkedlist/remove_range.py) -- [map : マップ](map) - - [hashtable](map/hashtable.py) - - [separate_chaining_hashtable](map/separate_chaining_hashtable.py) - - [longest_common_subsequence](map/longest_common_subsequence.py) - - [randomized_set](map/randomized_set.py) - - [valid_sudoku](map/valid_sudoku.py) -- [maths : 数学](maths) - - [base_conversion](maths/base_conversion.py) - - [extended_gcd](maths/extended_gcd.py) - - [gcd/lcm](maths/gcd.py) - - [generate_strobogrammtic](maths/generate_strobogrammtic.py) - - [is_strobogrammatic](maths/is_strobogrammatic.py) - - [next_bigger](maths/next_bigger.py) - - [next_perfect_square](maths/next_perfect_square.py) - - [nth_digit](maths/nth_digit.py) - - [prime_check](maths/prime_check.py) - - [primes_sieve_of_eratosthenes](maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](maths/pythagoras.py) - - [rabin_miller](maths/rabin_miller.py) - - [rsa](maths/rsa.py) - - [sqrt_precision_factor](maths/sqrt_precision_factor.py) - - [summing_digits](maths/summing_digits.py) -- [matrix : 行列](matrix) - - [sudoku_validator](matrix/sudoku_validator.py) - - [bomb_enemy](matrix/bomb_enemy.py) - - [copy_transform](matrix/copy_transform.py) - - [count_paths](matrix/count_paths.py) - - [matrix_rotation.txt](matrix/matrix_rotation.txt) - - [rotate_image](matrix/rotate_image.py) - - [search_in_sorted_matrix](matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](matrix/sparse_dot_vector.py) - - [sparse_mul](matrix/sparse_mul.py) - - [spiral_traversal](matrix/spiral_traversal.py) -- [queues : キュー](queues) - - [max_sliding_window](queues/max_sliding_window.py) - - [moving_average](queues/moving_average.py) - - [queue](queues/queue.py) - - [reconstruct_queue](queues/reconstruct_queue.py) - - [zigzagiterator](queues/zigzagiterator.py) -- [search : サーチ](search) - - [binary_search](search/binary_search.py) - - [first_occurance](search/first_occurance.py) - - [last_occurance](search/last_occurance.py) - - [search_insert](search/search_insert.py) - - [two_sum](search/two_sum.py) - - [search_range](search/search_range.py) - - [find_min_rotate](search/find_min_rotate.py) - - [search_rotate](search/search_rotate.py) -- [set : セット](set) - - [randomized_set](set/randomized_set.py) - - [set_covering](set/set_covering.py) -- [sort : ソート](sort) - - [bubble_sort](sort/bubble_sort.py) - - [comb_sort](sort/comb_sort.py) - - [counting_sort](sort/counting_sort.py) - - [heap_sort](sort/heap_sort.py) - - [insertion_sort](sort/insertion_sort.py) - - [meeting_rooms](sort/meeting_rooms.py) - - [merge_sort](sort/merge_sort.py) - - [quick_sort](sort/quick_sort.py) - - [selection_sort](sort/selection_sort.py) - - [sort_colors](sort/sort_colors.py) - - [topsort](sort/topsort.py) - - [wiggle_sort](sort/wiggle_sort.py) -- [stack : スタック](stack) - - [longest_abs_path](stack/longest_abs_path.py) - - [simplify_path](stack/simplify_path.py) - - [stack](stack/stack.py) - - [valid_parenthesis](stack/valid_parenthesis.py) - - [stutter](stack/stutter.py) - - [switch_pairs](stack/switch_pairs.py) - - [is_consecutive](stack/is_consecutive.py) - - [remove_min](stack/remove_min.py) - - [is_sorted](stack/is_sorted.py) -- [strings : 文字列](strings) - - [fizzbuzz](strings/fizzbuzz.py) - - [delete_reoccurring_characters](strings/delete_reoccurring_characters.py) - - [strip_url_params](strings/strip_url_params.py) - - [validate_coordinates](strings/validate_coordinates.py) - - [domain_extractor](strings/domain_extractor.py) - - [merge_string_checker](strings/merge_string_checker.py) - - [add_binary](strings/add_binary.py) - - [breaking_bad](strings/breaking_bad.py) - - [decode_string](strings/decode_string.py) - - [encode_decode](strings/encode_decode.py) - - [group_anagrams](strings/group_anagrams.py) - - [int_to_roman](strings/int_to_roman.py) - - [is_palindrome](strings/is_palindrome.py) - - [license_number](strings/license_number.py) - - [make_sentence](strings/make_sentence.py) - - [multiply_strings](strings/multiply_strings.py) - - [one_edit_distance](strings/one_edit_distance.py) - - [rabin_karp](strings/rabin_karp.py) - - [reverse_string](strings/reverse_string.py) - - [reverse_vowel](strings/reverse_vowel.py) - - [reverse_words](strings/reverse_words.py) - - [roman_to_int](strings/roman_to_int.py) - - [word_squares](strings/word_squares.py) -- [tree : 木構造](tree) - - [bst](tree/tree/bst) - - [array2bst](tree/bst/array2bst.py) - - [bst_closest_value](tree/bst/bst_closest_value.py) - - [BSTIterator](tree/bst/BSTIterator.py) - - [delete_node](tree/bst/delete_node.py) - - [is_bst](tree/bst/is_bst.py) - - [kth_smallest](tree/bst/kth_smallest.py) - - [lowest_common_ancestor](tree/bst/lowest_common_ancestor.py) - - [predecessor](tree/bst/predecessor.py) - - [serialize_deserialize](tree/bst/serialize_deserialize.py) - - [successor](tree/bst/successor.py) - - [unique_bst](tree/bst/unique_bst.py) - - [depth_sum](tree/bst/depth_sum.py) - - [count_left_node](tree/bst/count_left_node.py) - - [num_empty](tree/bst/num_empty.py) - - [height](tree/bst/height.py) - - [red_black_tree](tree/red_black_tree) - - [red_black_tree](tree/red_black_tree/red_black_tree.py) - - [segment_tree](tree/segment_tree) - - [segment_tree](tree/segment_tree/segment_tree.py) - - [traversal](tree/traversal) - - [inorder](tree/traversal/inorder.py) - - [level_order](tree/traversal/level_order.py) - - [zigzag](tree/traversal/zigzag.py) - - [trie](tree/trie) - - [add_and_search](tree/trie/add_and_search.py) - - [trie](tree/trie/trie.py) - - [binary_tree_paths](tree/binary_tree_paths.py) - - [bintree2list](tree/bintree2list.py) - - [deepest_left](tree/deepest_left.py) - - [invert_tree](tree/invert_tree.py) - - [is_balanced](tree/is_balanced.py) - - [is_subtree](tree/is_subtree.py) - - [is_symmetric](tree/is_symmetric.py) - - [longest_consecutive](tree/longest_consecutive.py) - - [lowest_common_ancestor](tree/lowest_common_ancestor.py) - - [max_height](tree/max_height.py) - - [max_path_sum](tree/max_path_sum.py) - - [min_height](tree/min_height.py) - - [path_sum](tree/path_sum.py) - - [path_sum2](tree/path_sum2.py) - - [pretty_print](tree/pretty_print.py) - - [same_tree](tree/same_tree.py) - - [tree](tree/tree.py) -- [union-find : 素集合データ構造](union-find) - - [count_islands](union-find/count_islands.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [find_difference](algorithms/bit/find_difference.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) +- [calculator : 計算機](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs : 深さ優先探索](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp : 動的計画法](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph : グラフ](algorithms/graph) + - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap : ヒープ](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist : 連結リスト](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map : マップ](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) +- [maths : 数学](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix : 行列](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues : キュー](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search : サーチ](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurance](algorithms/search/first_occurance.py) + - [last_occurance](algorithms/search/last_occurance.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) +- [set : セット](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) +- [sort : ソート](algorithms/sort) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [topsort](algorithms/sort/topsort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack : スタック](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings : 文字列](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) +- [tree : 木構造](algorithms/tree) + - [bst](algorithms/tree/tree/bst) + - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bintree2list](algorithms/tree/bintree2list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [union-find : 素集合データ構造](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) ## 貢献者 本リポジトリは次の方によって維持されています From cfc413232bdb82b696acf8272cb083e46e8527ef Mon Sep 17 00:00:00 2001 From: Conor Ryan Date: Sat, 2 Jun 2018 08:36:02 -0700 Subject: [PATCH 033/302] FIX README.md to correct link for the Arrays / Josephus Problem (#299) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b33ca6002..6006ba14a 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ If you want to uninstall algorithms, it is as simple as: - [delete_nth](algorithms/arrays/delete_nth.py) - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [josephus_problem](algorithms/arrays/josephus.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) From 23b35ff96d486e0d0fd3f9cc4364535bf7ba9d0b Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Sun, 3 Jun 2018 16:05:55 +0900 Subject: [PATCH 034/302] Corrected link to Arrays/Josephus Problems (#300) * Update README_JP.md * Update README_CN.md * Update README_GE.md --- README_CN.md | 2 +- README_GE.md | 2 +- README_JP.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README_CN.md b/README_CN.md index 166414b84..d6e3340ba 100644 --- a/README_CN.md +++ b/README_CN.md @@ -69,7 +69,7 @@ pip3 uninstall -y algorithms - [delete_nth: 删除第n项](algorithms/arrays/delete_nth.py) - [flatten:数组降维](algorithms/arrays/flatten.py) - [garage:停车场](algorithms/arrays/garage.py) - - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus_problem.py) + - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus.py) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) diff --git a/README_GE.md b/README_GE.md index 02cfdb906..a25715537 100644 --- a/README_GE.md +++ b/README_GE.md @@ -63,7 +63,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [delete_nth](algorithms/arrays/delete_nth.py) - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [josephus_problem](algorithms/arrays/josephus.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) diff --git a/README_JP.md b/README_JP.md index 4804b5fc5..d2e30aade 100644 --- a/README_JP.md +++ b/README_JP.md @@ -53,7 +53,7 @@ if __name__ == "__main__": - [delete_nth](algorithms/arrays/delete_nth.py) - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [josephus_problem](algorithms/arrays/josephus.py) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [merge_intervals](algorithms/arrays/merge_intervals.py) From 887a5bd1b9593219bcfcc06318e7b0ab561e91b9 Mon Sep 17 00:00:00 2001 From: hsi1032 Date: Sun, 3 Jun 2018 18:52:45 +0900 Subject: [PATCH 035/302] Create README_KR.md file that is korean translation of README.md (#297) * Create README_KR.md --- README_KR.md | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 README_KR.md diff --git a/README_KR.md b/README_KR.md new file mode 100644 index 000000000..a2b408a11 --- /dev/null +++ b/README_KR.md @@ -0,0 +1,317 @@ +English(README_EN.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) + +Python 버전 자료구조 및 알고리즘 +========================================= + +Python 3로 구현한 간단하고 명확한 자료구조와 알고리즘들의 예제 입니다. + +## 기여 활동 +프로젝트 활동 참여에 관심을 가져주셔서 감사합니다! 여러가지 방법으로 이 프로젝트에 기여해주세요. [기여 방법 소개](CONTRIBUTING.md) + + +## 테스트 종류들 + +### 단위별 테스트 사용 +아래 명시된 모든 테스트 실행하기: + + $ python3 -m unittest discover tests + +특정 테스트 실행하기 위해선 아래 코드로 실행할 수 있습니다 (예시: sort): + + $ python3 -m unittest tests.test_sort + +### pytest 사용 +아래 명시된 모든 테스트 실행하기: + + $ python3 -m pytest tests + +## 알고리즘 설치 +만약 API 알고리즘들을 당신의 코드에 사용하기를 원한다면, 아래 코드로 간단하게 실행할 수 있습니다: + + $ pip3 install git+https://github.com/keon/algorithms + +그리고 python 파일을 만듦으로 테스트할 수 있습니다: (예시: 'sort'안에서 'merge_sort'사용) + +```python3 +from sort import merge_sort + +if __name__ == "__main__": + my_list = [1, 8, 3, 5, 6] + my_list = merge_sort.merge_sort(my_list) + print(my_list) +``` + +## 알고리즘 삭제 +만약 당신이 알고리즘들을 삭제하기 원한다면, 아래 코드로 간단하게 실행할 수 있습니다: + + $ pip3 uninstall -y algorithms + +## 구현 알고리즘 목록 + +- [arrays : 배열](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) + - [rotate_array](algorithms/arrays/rotate_array.py) + - [summary_ranges](algorithms/arrays/summary_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) +- [backtrack : 백트래킹](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs : 너비 우선 탐색](algorithms/bfs) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit : 비트](algorithms/bit) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [find_difference](algorithms/bit/find_difference.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) +- [calculator : 계산기](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs : 깊이 우선 탐색](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp : 동적 계획법](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph : 그래프](algorithms/graph) + - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap : 힙](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist : 연결 리스트](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map : 맵](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) +- [maths : 수학 계산](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix : 행렬](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues : 큐](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search : 탐색 알고리즘](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurance](algorithms/search/first_occurance.py) + - [last_occurance](algorithms/search/last_occurance.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) +- [set : 집합](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) +- [sort : 정렬 알고리즘](algorithms/sort) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [topsort](algorithms/sort/topsort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack : 스택](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings : 문자열](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) +- [tree : 트리](algorithms/tree) + - [bst : 이진 탐색 트리](algorithms/tree/tree/bst) + - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree : 레드 블랙 트리](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree : 세그먼트 트리](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal : 트리 순회](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie : 트라이](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bintree2list](algorithms/tree/bintree2list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [union-find : 합집합 찾기](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) + +## 기여자들 +이 저장소는 아래 사람들에 의해 유지되고 있습니다. + +* [Keon Kim](https://github.com/keon) +* [Rahul Goswami](https://github.com/goswami-rahul) +* [Christian Bender](https://github.com/christianbender) +* [Ankit Agarwal](https://github.com/ankit167) +* [Hai Hoang Dang](https://github.com/danghai) +* [Saad](https://github.com/SaadBenn) + +그리고 이 저장소를 만드는데 도움을 준 [모든 기여자](https://github.com/keon/algorithms/graphs/contributors) +분 들에게 감사를 표합니다. From e414353a85a64cdc6f01a6ed601c41bf4bfd790e Mon Sep 17 00:00:00 2001 From: Han SangWook <9967han@naver.com> Date: Mon, 4 Jun 2018 01:38:12 +0900 Subject: [PATCH 036/302] Added link to Korean README file in other README files (#302) * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md --- README.md | 2 +- README_CN.md | 2 +- README_GE.md | 2 +- README_JP.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6006ba14a..231facdad 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) +English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) diff --git a/README_CN.md b/README_CN.md index d6e3340ba..130898a66 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) +[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) Python版数据结构和算法 ========================================= diff --git a/README_GE.md b/README_GE.md index a25715537..5380e65a9 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) +[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) diff --git a/README_JP.md b/README_JP.md index d2e30aade..f50d6df18 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) pythonのデータ構造とアルゴリズム ========================================= From bb9d6c195665abbcd2e52d2e712d8632142b7fa7 Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Mon, 4 Jun 2018 20:37:07 +0900 Subject: [PATCH 037/302] Created combination.py in maths (#304) * Create combination.py * Update __init__.py * Update test_maths.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 3 ++- README_KR.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/combination.py | 6 ++++++ tests/test_maths.py | 14 +++++++++++++- 8 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 algorithms/maths/combination.py diff --git a/README.md b/README.md index 231facdad..3814933ba 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ If you want to uninstall algorithms, it is as simple as: - [valid_sudoku](algorithms/map/valid_sudoku.py) - [maths](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) diff --git a/README_CN.md b/README_CN.md index 130898a66..5427972c8 100644 --- a/README_CN.md +++ b/README_CN.md @@ -164,6 +164,7 @@ pip3 uninstall -y algorithms - [valid_sudoku:有效数独](algorithms/map/valid_sudoku.py) - [math:数学问题](algorithms/maths) - [extended_gcd:扩展欧几里得算法](algorithms/maths/extended_gcd.py) + - [combination](algorithms/maths/combination.py) - [gcd/lcm:最大公约数和最小公倍数](algorithms/maths/gcd.py) - [prime_test:主要测试](algorithms/maths/prime_test.py) - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](algorithms/maths/primes_sieve_of_eratosthenes.py) diff --git a/README_GE.md b/README_GE.md index 5380e65a9..bd9c46995 100644 --- a/README_GE.md +++ b/README_GE.md @@ -179,6 +179,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [valid_sudoku](algorithms/map/valid_sudoku.py) - [maths](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) diff --git a/README_JP.md b/README_JP.md index f50d6df18..393e0bb44 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,6 +1,6 @@ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) -pythonのデータ構造とアルゴリズム +Pythonのデータ構造とアルゴリズム ========================================= Python 3で開発された簡単で明確なデータ構造とアルゴリズムの例を紹介します。 @@ -169,6 +169,7 @@ if __name__ == "__main__": - [valid_sudoku](algorithms/map/valid_sudoku.py) - [maths : 数学](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) diff --git a/README_KR.md b/README_KR.md index a2b408a11..dd1bfb852 100644 --- a/README_KR.md +++ b/README_KR.md @@ -165,6 +165,7 @@ if __name__ == "__main__": - [valid_sudoku](algorithms/map/valid_sudoku.py) - [maths : 수학 계산](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 6716384ba..d791ad864 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -9,3 +9,4 @@ from .pythagoras import * from .rabin_miller import * from .rsa import * +from .combination import * diff --git a/algorithms/maths/combination.py b/algorithms/maths/combination.py new file mode 100644 index 000000000..ea9e4b37f --- /dev/null +++ b/algorithms/maths/combination.py @@ -0,0 +1,6 @@ +def combination(n, r): + # This function calculates nCr + if n == r or r == 0: + return 1 + else: + return combination(n-1, r-1) + combination(n-1, r) diff --git a/tests/test_maths.py b/tests/test_maths.py index afafd2ec5..fbf0772aa 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -9,7 +9,8 @@ primes, pythagoras, is_prime, - encrypt, decrypt, generate_key + encrypt, decrypt, generate_key, + combination ) import unittest @@ -202,6 +203,17 @@ def test_encrypt_decrypt(self): # dec = decrypt(en, d, n) # self.assertEqual(data,dec) +class TestCombination(unittest.TestCase): + """[summary] + Test for the file rsa.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_combination(self): + self.assertEqual(10, combination(5, 2)) + self.assertEqual(252, combination(10, 5)) + if __name__ == "__main__": unittest.main() From 4a3cbb70bb254f8089c3a596ee220ff3f97f714f Mon Sep 17 00:00:00 2001 From: aig031 <31883686+aig031@users.noreply.github.com> Date: Mon, 4 Jun 2018 21:42:09 +0900 Subject: [PATCH 038/302] Created radix_sort.py in algorithms/sort (#303) * Create radix_sort.py * Update test_sort.py * Update __init__.py * Update radix_sort.py * Update radix_sort.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/radix_sort.py | 26 ++++++++++++++++++++++++++ tests/test_sort.py | 7 ++++++- 8 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 algorithms/sort/radix_sort.py diff --git a/README.md b/README.md index 3814933ba..c6011f84c 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,7 @@ If you want to uninstall algorithms, it is as simple as: - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) diff --git a/README_CN.md b/README_CN.md index 5427972c8..91451ff89 100644 --- a/README_CN.md +++ b/README_CN.md @@ -208,6 +208,7 @@ pip3 uninstall -y algorithms - [meeting_rooms:会议室](algorithms/sort/meeting_rooms.py) - [merge_sort:归并排序](algorithms/sort/merge_sort.py) - [quick_sort:快速排序](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort:选择排序](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors:颜色排序](algorithms/sort/sort_colors.py) diff --git a/README_GE.md b/README_GE.md index bd9c46995..89922c555 100644 --- a/README_GE.md +++ b/README_GE.md @@ -233,6 +233,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) diff --git a/README_JP.md b/README_JP.md index 393e0bb44..3083d72d3 100644 --- a/README_JP.md +++ b/README_JP.md @@ -223,6 +223,7 @@ if __name__ == "__main__": - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) diff --git a/README_KR.md b/README_KR.md index dd1bfb852..0b4c59982 100644 --- a/README_KR.md +++ b/README_KR.md @@ -218,6 +218,7 @@ if __name__ == "__main__": - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - [topsort](algorithms/sort/topsort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index 665a0d70d..39eb1478b 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -8,3 +8,4 @@ from .selection_sort import * from .bucket_sort import * from .shell_sort import * +from .radix_sort import * diff --git a/algorithms/sort/radix_sort.py b/algorithms/sort/radix_sort.py new file mode 100644 index 000000000..fee0f2f7f --- /dev/null +++ b/algorithms/sort/radix_sort.py @@ -0,0 +1,26 @@ +""" +radix sort +complexity: O(nk) . n is the size of input list and k is the digit length of the number +""" +def radix_sort(arr): + is_done = False + position = 1 + + while not is_done: + queue_list = [list() for _ in range(10)] + is_done = True + + for num in arr: + digit_number = num // position % 10 + queue_list[digit_number].append(num) + if is_done and digit_number > 0: + is_done = False + + index = 0 + for numbers in queue_list: + for num in numbers: + arr[index] = num + index += 1 + + position *= 10 + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index 43d5bf29e..4665259ab 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -8,7 +8,8 @@ quick_sort, selection_sort, bucket_sort, - shell_sort + shell_sort, + radix_sort ) import unittest @@ -59,6 +60,10 @@ def test_shell_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], shell_sort([1, 5, 65, 23, 57, 1232])) + def test_radix_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + radix_sort([1, 5, 65, 23, 57, 1232])) + if __name__ == "__main__": From 97e5e85cedd11ce8353a4f68edc5dcd943e061fb Mon Sep 17 00:00:00 2001 From: Roger Li Date: Tue, 5 Jun 2018 00:07:56 -0400 Subject: [PATCH 039/302] Zhengli0817 patch 1 - update topsort.py (#295) * Update bst.py * Update topsort.py The original algo is wrong because it is using BFS, it should use DFS instead. A counter-example is provided below: depGraph = { "a" : [ "b" ], "b" : [ "c" ], "c" : [ 'e'], 'e' : [ 'g' ], "d" : [ ], "f" : ["e" , "d"], "g" : [ ] } given = [ "b", "c", "a", "d", "e", "f", "g" ] The output of ret_dep_graph() is: ['e', 'g', 'c', 'b', 'a', 'd', 'f'] Clearly, 'g' has to be done before 'e'. * Update topsort.py * Update topsort.py The original algo in topsort.py is wrong because it is using BFS, it should use DFS instead. A counter-example is provided below: depGraph = { "a" : [ "b" ], "b" : [ "c" ], "c" : [ 'e'], 'e' : [ 'g' ], "d" : [ ], "f" : ["e" , "d"], "g" : [ ] } given = [ "b", "c", "a", "d", "e", "f", "g" ] The output of ret_dep_graph() is: ['e', 'g', 'c', 'b', 'a', 'd', 'f'] Clearly, 'g' has to be done before 'e'. * Update topsort.py * Create __init__.py * Update __init__.py * Update __init__.py * Create test_topsort.py * Update topsort.py * Update test_topsort.py * Update __init__.py * Update and rename topsort.py to top_sort.py * Update top_sort.py * Update __init__.py * Update test_topsort.py --- algorithms/sort/__init__.py | 1 + algorithms/sort/top_sort.py | 66 +++++++++++++++++++++++++++++++++++++ algorithms/sort/topsort.py | 60 --------------------------------- tests/graph/__init__.py | 1 + tests/graph/test_topsort.py | 27 +++++++++++++++ 5 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 algorithms/sort/top_sort.py delete mode 100644 algorithms/sort/topsort.py create mode 100644 tests/graph/__init__.py create mode 100644 tests/graph/test_topsort.py diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index 39eb1478b..d86e2bce3 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -6,6 +6,7 @@ from .merge_sort import * from .quick_sort import * from .selection_sort import * +from .top_sort import * from .bucket_sort import * from .shell_sort import * from .radix_sort import * diff --git a/algorithms/sort/top_sort.py b/algorithms/sort/top_sort.py new file mode 100644 index 000000000..b9188bb28 --- /dev/null +++ b/algorithms/sort/top_sort.py @@ -0,0 +1,66 @@ +GRAY, BLACK = 0, 1 + +def top_sort_recursive(graph): + """ Time complexity is the same as DFS, which is O(V + E) + Space complexity: O(V) + """ + order, enter, state = [], set(graph), {} + + def dfs(node): + state[node] = GRAY + #print(node) + for k in graph.get(node, ()): + sk = state.get(k, None) + if sk == GRAY: + raise ValueError("cycle") + if sk == BLACK: + continue + enter.discard(k) + dfs(k) + order.append(node) + state[node] = BLACK + + while enter: dfs(enter.pop()) + return order + +def top_sort(graph): + """ Time complexity is the same as DFS, which is O(V + E) + Space complexity: O(V) + """ + order, enter, state = [], set(graph), {} + + def is_ready(node): + lst = graph.get(node, ()) + if len(lst) == 0: + return True + for k in lst: + sk = state.get(k, None) + if sk == GRAY: + raise ValueError("cycle") + if sk != BLACK: + return False + return True + + while enter: + node = enter.pop() + stack = [] + while True: + state[node] = GRAY + stack.append(node) + for k in graph.get(node, ()): + sk = state.get(k, None) + if sk == GRAY: + raise ValueError("cycle") + if sk == BLACK: + continue + enter.discard(k) + stack.append(k) + while stack and is_ready(stack[-1]): + node = stack.pop() + order.append(node) + state[node] = BLACK + if len(stack) == 0: + break + node = stack.pop() + + return order diff --git a/algorithms/sort/topsort.py b/algorithms/sort/topsort.py deleted file mode 100644 index 8341ce941..000000000 --- a/algorithms/sort/topsort.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Given a list of system packages, -some packages cannot be installed until the other packages are installed. -Provide a valid sequence to install all of the packages. - -e.g. -a relies on b -b relies on c - -then a valid sequence is [c, b, a] -""" - -depGraph = { - - "a": ["b"], - "b": ["c"], - "c": ['e'], - 'e': [], - "d": [], - "f": ["e", "d"] -} - -given = ["b", "c", "a", "d", "e", "f"] - - -def ret_deps(visited, start): - queue = [] - out = [] - queue.append(start) - while queue: - new_node = queue.pop(0) - if new_node not in visited: - visited.add(new_node) - for child in depGraph[new_node]: - queue.append(child) - out.append(child) - out.append(start) - return out - - -def ret_dep_graph(): - visited = set() - out = [] - # visited.add(given[0]) - for pac in given: - if pac in visited: - continue - visited.add(pac) - # out.append(pac) - if pac in depGraph: - # find all children - for child in depGraph[pac]: - if child in visited: - continue - out.extend(ret_deps(visited, child)) - out.append(pac) - print(out) - - -ret_dep_graph() diff --git a/tests/graph/__init__.py b/tests/graph/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/tests/graph/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/graph/test_topsort.py b/tests/graph/test_topsort.py new file mode 100644 index 000000000..a308ed306 --- /dev/null +++ b/tests/graph/test_topsort.py @@ -0,0 +1,27 @@ +from algorithms.sort import ( + top_sort, top_sort_recursive +) + +import unittest + +class TestSuite(unittest.TestCase): + def setUp(self): + self.depGraph = { + "a" : [ "b" ], + "b" : [ "c" ], + "c" : [ 'e'], + 'e' : [ 'g' ], + "d" : [ ], + "f" : ["e" , "d"], + "g" : [ ] + } + + def test_topsort(self): + res = top_sort_recursive(self.depGraph) + #print(res) + self.assertTrue(res.index('g') < res.index('e')) + res = top_sort(self.depGraph) + self.assertTrue(res.index('g') < res.index('e')) + +if __name__ == '__main__': + unittest.main() From 8f68ac88333400930c3417d37ff30e9dc72b8b7c Mon Sep 17 00:00:00 2001 From: aig031 <31883686+aig031@users.noreply.github.com> Date: Tue, 5 Jun 2018 13:10:32 +0900 Subject: [PATCH 040/302] Created CONTRIBUTING_KR.md in Korean (#290) * Update CONTRIBUTING_KR.md --- CONTRIBUTING_KR.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 CONTRIBUTING_KR.md diff --git a/CONTRIBUTING_KR.md b/CONTRIBUTING_KR.md new file mode 100644 index 000000000..522f0e5b9 --- /dev/null +++ b/CONTRIBUTING_KR.md @@ -0,0 +1,66 @@ +# 기여 활동 + +모든 pull request는 환영입니다. 이 저장소에 기여 함으로써, 당신은 [code of conduct](CODE_OF_CONDUCT.md) +를 준수하는 것에 동의 한 것입니다. + + +## 시작하기 + +* 우선 이 저장소를 [fork][fork] 하시고, 이를 사용하기 위해서 다음과 같이 clone 주세요: + + git clone git@github.com:your-username/algorithms.git + +* 그리고 새로운 내용을 더할 branch를 만들어주세요. 예를 들어: + * add_XXX 만약 당신이 새로운 알고리즘이나 자료 구조를 추가 했을 경우. + * fix_XXX 만약 당신이 어떤 알고리즘이나 자료 구조에서 고쳐야할 bug를 발견했을 경우. + * test_XXX 만약 당신이 test/s를 작성한 경우. + +당신은 다음과 같이 기여할 수 있습니다: +- 새로운 알고리즘을 구현해주세요. 그리고, 그것을 정확히 분류해주세요(e.g. [array](array), [dp](dp), etc). +만약 당신의 알고리즘이 어떤 섹션에도 포함이 되지 않는다면, 새로운 섹션을 만들어 주세요. 단, 당신의 알고리즘이 제대로 작동하는지 +확인해주세요. +- 알고리즘들을 최적화하거나 향상시켜주세요. +- 문제들에 대해서 다른 해결 법을 추가해주세요. +- 버그들을 찾거나 고쳐주세요. +- 알고리즘들을 더 잘 설명하기 위한 새로운 예시들을 추가해주세요. +- test cases를 추가해주세요. + +## Pull Requests +당신의 fork에 push 하고 pull request를 제출하세요 [submit a pull request][pr]. + +우리는 이를 검토할 것이며, 변화, 개량, 혹은 대안을 제시할 수 도 있습니다. +여기에 당신의 pull request가 허용될 가능성을 높여주는 몇몇 요소들이 있습니다: + +* 모든 알고리즘들은 **Python 3**로 작성되어야 합니다. +(몇몇 알고리즘들은 여전히 _python 2_ 로 작성되어져 있습니다. 당신은 이를 Python 3으로 번역함으로써 저희에게 기여 해주실 수도 있습니다. +[those][issue120] to _Python 3_.) +* 깔끔하고 이해할 수 있는 코드를 작성해주세요. +* 코드에 대해 올바르게 주석 처리 해 주시고, 알고리즘이 수행하는 작업에 대해서 [docstrings][docstr]에서 설명해 주세요. +* 당신은 간단한 예시를 제시함으로써 출력 값에 대하여 설명하실 수도 있습니다. +* 또한 가능하다면 알고리즘에 대하여, 두 가지의 test cases를 포함 시켜주세요. +* [good commit message][commit]를 작성해주세요. + + +## Issues +만약 추가해야 할 알고리즘이 있거나, 현재 저희 프로젝트의 어떤 알고리즘에서 버그가 발견된다면 [new issue][newissue]에 이를 추가해주세요. 새로운 issue를 제안하기 전에 중복된 issue을 발생을 피하기 위해서 [existing issues][issues]를 확인해주세요. 또한, 현재 존재하는 issue를 해결하는 것을 고려해주시거나 issue에 대한 토의에 기여해주세요. + +## Collaborators +저희 협업자 들에게 어떤 도움이나 확인이 필요하다면, 위 주소로 물어봐주세요. + +[Keon Kim](https://github.com/keon) + +[Rahul Goswami](https://github.com/goswami-rahul) + +[Ankit Agarwal](https://github.com/ankit167) + +[Hai Hoang Dang](https://github.com/danghai) + +[Saad](https://github.com/SaadBenn) + +[fork]: https://help.github.com/articles/fork-a-repo/ +[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings +[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[pr]: https://github.com/keon/algorithms/compare/ +[newissue]: https://github.com/keon/algorithms/issues/new +[issue120]: https://github.com/keon/algorithms/issues/120 +[issues]: https://github.com/keon/algorithms/issues/ From dec867e8329d7bac74424039a693633d6e119b16 Mon Sep 17 00:00:00 2001 From: ppuzzle Date: Tue, 5 Jun 2018 19:04:10 +0900 Subject: [PATCH 041/302] Create linear_search.py in algorithms/search (#305) * Create linear_search.py * Update linear_search.py * Update linear_search.py * Update README.md * Update README.md * Update test_search.py * Update __init__.py --- README.md | 1 + algorithms/search/__init__.py | 1 + algorithms/search/linear_search.py | 13 +++++++++++++ tests/test_search.py | 8 ++++++++ 4 files changed, 23 insertions(+) create mode 100644 algorithms/search/linear_search.py diff --git a/README.md b/README.md index c6011f84c..aff2cd5af 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ If you want to uninstall algorithms, it is as simple as: - [binary_search](algorithms/search/binary_search.py) - [first_occurance](algorithms/search/first_occurance.py) - [last_occurance](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) - [search_insert](algorithms/search/search_insert.py) - [two_sum](algorithms/search/two_sum.py) - [search_range](algorithms/search/search_range.py) diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index cebea34fd..89bea2dc8 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -1,6 +1,7 @@ from .binary_search import * from .first_occurance import * from .last_occurance import * +from .linear_search import * from .search_insert import * from .two_sum import * from .search_range import * diff --git a/algorithms/search/linear_search.py b/algorithms/search/linear_search.py new file mode 100644 index 000000000..da4d9b93c --- /dev/null +++ b/algorithms/search/linear_search.py @@ -0,0 +1,13 @@ +# +# Linear search works in any array. +# +# T(n): O(n) +# + +def linear_search(array, query): + length = len(array) + for i in range(length): + if array[i] == query: + return i + + return -1 diff --git a/tests/test_search.py b/tests/test_search.py index 4567ec559..360397faf 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -2,6 +2,7 @@ binary_search, binary_search_recur, first_occurance, last_occurance, + linear_search, search_insert, two_sum, two_sum1, two_sum2, search_range, @@ -44,6 +45,13 @@ def test_last_occurance(self): self.assertEqual(None, last_occurance(array, 7)) self.assertEqual(0, last_occurance(array, 1)) self.assertEqual(13, last_occurance(array, 6)) + + def test_linear_search(self): + array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6, 6, 6] + self.assertEqual(6, linear_search(array, 4)) + self.assertEqual(10, linear_search(array, 5)) + self.assertEqual(-1, linear_search(array, 7)) + self.assertEqual(-1, linear_search(array, -1)) def test_search_insert(self): array = [1,3,5,6] From 0a86bfd62dda5e116108cb430f34c02984580192 Mon Sep 17 00:00:00 2001 From: hsi1032 Date: Tue, 5 Jun 2018 19:04:47 +0900 Subject: [PATCH 042/302] Created jump_seach in algorithms/seach (#301) * Add files via upload * Update __init__.py * Update test_search.py * Create README_KR.md * Update README_KR.md * Update jump_search.py * Update jump_search.py * Update test_search.py * Update jump_search.py * Update README_KR.md update jump search * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 5 ++-- algorithms/search/__init__.py | 1 + algorithms/search/jump_search.py | 40 ++++++++++++++++++++++++++++++++ tests/test_search.py | 10 +++++++- 8 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 algorithms/search/jump_search.py diff --git a/README.md b/README.md index aff2cd5af..3c9cefeb0 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,7 @@ If you want to uninstall algorithms, it is as simple as: - [search_range](algorithms/search/search_range.py) - [find_min_rotate](algorithms/search/find_min_rotate.py) - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) - [set](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) diff --git a/README_CN.md b/README_CN.md index 91451ff89..45d476086 100644 --- a/README_CN.md +++ b/README_CN.md @@ -195,6 +195,7 @@ pip3 uninstall -y algorithms - [count_elem:元素计数](algorithms/search/count_elem.py) - [first_occurance:首次出现](algorithms/search/first_occurance.py) - [last_occurance:最后一次出现](algorithms/search/last_occurance.py) + - [jump_search](algorithms/search/jump_search.py) - [set:集合](algorithms/set) - [randomized_set:随机集合](algorithms/set/randomized_set.py) - [set_covering:集合覆盖](algorithms/set/set_covering.py) diff --git a/README_GE.md b/README_GE.md index 89922c555..b83364139 100644 --- a/README_GE.md +++ b/README_GE.md @@ -220,6 +220,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [search_range](algorithms/search/search_range.py) - [find_min_rotate](algorithms/search/find_min_rotate.py) - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) - [set](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) diff --git a/README_JP.md b/README_JP.md index 3083d72d3..de78c1c68 100644 --- a/README_JP.md +++ b/README_JP.md @@ -210,6 +210,7 @@ if __name__ == "__main__": - [search_range](algorithms/search/search_range.py) - [find_min_rotate](algorithms/search/find_min_rotate.py) - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) - [set : セット](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) diff --git a/README_KR.md b/README_KR.md index 0b4c59982..871b2728e 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,4 +1,4 @@ -English(README_EN.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) Python 버전 자료구조 및 알고리즘 ========================================= @@ -11,7 +11,7 @@ Python 3로 구현한 간단하고 명확한 자료구조와 알고리즘들의 ## 테스트 종류들 -### 단위별 테스트 사용 +### unittest 사용 아래 명시된 모든 테스트 실행하기: $ python3 -m unittest discover tests @@ -206,6 +206,7 @@ if __name__ == "__main__": - [search_range](algorithms/search/search_range.py) - [find_min_rotate](algorithms/search/find_min_rotate.py) - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) - [set : 집합](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index 89bea2dc8..ec3a78326 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -7,3 +7,4 @@ from .search_range import * from .find_min_rotate import * from .search_rotate import * +from .jump_search import * diff --git a/algorithms/search/jump_search.py b/algorithms/search/jump_search.py new file mode 100644 index 000000000..66f726a50 --- /dev/null +++ b/algorithms/search/jump_search.py @@ -0,0 +1,40 @@ +import math + +def jump_search(arr,target): + """Jump Search + Worst-case Complexity: O(√n) (root(n)) + All items in list must be sorted like binary search + + Find block that contains target value and search it linearly in that block + It returns a first target value in array + + reference: https://en.wikipedia.org/wiki/Jump_search + + """ + n = len(arr) + block_size = int(math.sqrt(n)) + block_prev = 0 + block= block_size + + # return -1 means that array doesn't contain taget value + # find block that contains target value + + if arr[n - 1] < target: + return -1 + while block <= n and arr[block - 1] < target: + block_prev = block + block += block_size + + # find target value in block + + while arr[block_prev] < target : + block_prev += 1 + if block_prev == min(block, n) : + return -1 + + # if there is target value in array, return it + + if arr[block_prev] == target : + return block_prev + else : + return -1 diff --git a/tests/test_search.py b/tests/test_search.py index 360397faf..c9f18eef7 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -7,7 +7,8 @@ two_sum, two_sum1, two_sum2, search_range, find_min_rotate, find_min_rotate_recur, - search_rotate, search_rotate_recur + search_rotate, search_rotate_recur, + jump_search ) import unittest @@ -96,6 +97,13 @@ def test_search_rotate(self): self.assertEqual(8, search_rotate_recur(array, 0, 11, 5)) self.assertEqual(-1, search_rotate_recur(array, 0, 11, 9)) + def test_jump_search(self): + array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6] + self.assertEqual(10, jump_search(array, 5)) + self.assertEqual(2, jump_search(array, 3)) + self.assertEqual(-1, jump_search(array, 7)) + self.assertEqual(-1, jump_search(array, -1)) + if __name__ == '__main__': unittest.main() From f88e4999bdf41c9bfb21165b6a7fb1725dedb7a4 Mon Sep 17 00:00:00 2001 From: ppuzzle Date: Tue, 5 Jun 2018 22:14:00 +0900 Subject: [PATCH 043/302] Added link to linear search in all README files (#307) * Update README_CN.md Added linear_search.py * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + 4 files changed, 4 insertions(+) diff --git a/README_CN.md b/README_CN.md index 45d476086..8f7aee009 100644 --- a/README_CN.md +++ b/README_CN.md @@ -195,6 +195,7 @@ pip3 uninstall -y algorithms - [count_elem:元素计数](algorithms/search/count_elem.py) - [first_occurance:首次出现](algorithms/search/first_occurance.py) - [last_occurance:最后一次出现](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) - [jump_search](algorithms/search/jump_search.py) - [set:集合](algorithms/set) - [randomized_set:随机集合](algorithms/set/randomized_set.py) diff --git a/README_GE.md b/README_GE.md index b83364139..da3272b6c 100644 --- a/README_GE.md +++ b/README_GE.md @@ -215,6 +215,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [binary_search](algorithms/search/binary_search.py) - [first_occurance](algorithms/search/first_occurance.py) - [last_occurance](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) - [search_insert](algorithms/search/search_insert.py) - [two_sum](algorithms/search/two_sum.py) - [search_range](algorithms/search/search_range.py) diff --git a/README_JP.md b/README_JP.md index de78c1c68..9eb25e048 100644 --- a/README_JP.md +++ b/README_JP.md @@ -205,6 +205,7 @@ if __name__ == "__main__": - [binary_search](algorithms/search/binary_search.py) - [first_occurance](algorithms/search/first_occurance.py) - [last_occurance](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) - [search_insert](algorithms/search/search_insert.py) - [two_sum](algorithms/search/two_sum.py) - [search_range](algorithms/search/search_range.py) diff --git a/README_KR.md b/README_KR.md index 871b2728e..7dd07f24f 100644 --- a/README_KR.md +++ b/README_KR.md @@ -201,6 +201,7 @@ if __name__ == "__main__": - [binary_search](algorithms/search/binary_search.py) - [first_occurance](algorithms/search/first_occurance.py) - [last_occurance](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) - [search_insert](algorithms/search/search_insert.py) - [two_sum](algorithms/search/two_sum.py) - [search_range](algorithms/search/search_range.py) From 59db1063715533ec752d12a8b66e62358678796b Mon Sep 17 00:00:00 2001 From: ppuzzle Date: Wed, 6 Jun 2018 01:39:29 +0900 Subject: [PATCH 044/302] Created factorial.py in algorithms/maths (#309) * Create factorial.py * Update __init__.py * Update test_maths.py * Update test_maths.py I added TestFactorial, also modified TestCombination comment. * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_maths.py * Update factorial.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/factorial.py | 20 ++++++++++++++++++++ tests/test_maths.py | 23 ++++++++++++++++++++++- 8 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 algorithms/maths/factorial.py diff --git a/README.md b/README.md index 3c9cefeb0..c3fcb0aea 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,7 @@ If you want to uninstall algorithms, it is as simple as: - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) diff --git a/README_CN.md b/README_CN.md index 8f7aee009..e1a866f32 100644 --- a/README_CN.md +++ b/README_CN.md @@ -165,6 +165,7 @@ pip3 uninstall -y algorithms - [math:数学问题](algorithms/maths) - [extended_gcd:扩展欧几里得算法](algorithms/maths/extended_gcd.py) - [combination](algorithms/maths/combination.py) + - [factorial](algorithms/maths/factorial.py) - [gcd/lcm:最大公约数和最小公倍数](algorithms/maths/gcd.py) - [prime_test:主要测试](algorithms/maths/prime_test.py) - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](algorithms/maths/primes_sieve_of_eratosthenes.py) diff --git a/README_GE.md b/README_GE.md index da3272b6c..17cb14825 100644 --- a/README_GE.md +++ b/README_GE.md @@ -181,6 +181,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) diff --git a/README_JP.md b/README_JP.md index 9eb25e048..043c4bcda 100644 --- a/README_JP.md +++ b/README_JP.md @@ -171,6 +171,7 @@ if __name__ == "__main__": - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) diff --git a/README_KR.md b/README_KR.md index 7dd07f24f..45e2eafef 100644 --- a/README_KR.md +++ b/README_KR.md @@ -167,6 +167,7 @@ if __name__ == "__main__": - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index d791ad864..2bf44a78f 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -1,5 +1,6 @@ from .base_conversion import * from .extended_gcd import * +from .factorial import * from .gcd import * from .generate_strobogrammtic import * from .is_strobogrammatic import * diff --git a/algorithms/maths/factorial.py b/algorithms/maths/factorial.py new file mode 100644 index 000000000..2cd1a3491 --- /dev/null +++ b/algorithms/maths/factorial.py @@ -0,0 +1,20 @@ +# +# This function calculates n! +# Factorial function not works in less than 0 +# + +def factorial(n): + + result = 1 + for i in range(2, n+1): + result *= i + + return result + + +def factorial_recur(n): + if n == 0: + return 1 + + return n * factorial(n-1) + diff --git a/tests/test_maths.py b/tests/test_maths.py index fbf0772aa..a5ca21fda 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,6 +1,7 @@ from algorithms.maths import ( int2base, base2int, extended_gcd, + factorial, factorial_recur, gcd, lcm, gen_strobogrammatic, strobogrammatic_in_range, is_strobogrammatic, is_strobogrammatic2, @@ -205,7 +206,7 @@ def test_encrypt_decrypt(self): class TestCombination(unittest.TestCase): """[summary] - Test for the file rsa.py + Test for the file combination.py Arguments: unittest {[type]} -- [description] @@ -215,5 +216,25 @@ def test_combination(self): self.assertEqual(10, combination(5, 2)) self.assertEqual(252, combination(10, 5)) +class TestFactorial(unittest.TestCase): + """[summary] + Test for the file factorial.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_factorial(self): + self.assertEqual(1, factorial(0)) + self.assertEqual(120, factorial(5)) + self.assertEqual(3628800, factorial(10)) + + def test_factorial_recur(self): + self.assertEqual(1, factorial_recur(0)) + self.assertEqual(120, factorial_recur(5)) + self.assertEqual(3628800, factorial_recur(10)) + if __name__ == "__main__": unittest.main() + + From 3e14809acb04343810efd12f0d5c01b8473f02ff Mon Sep 17 00:00:00 2001 From: Han SangWook <9967han@naver.com> Date: Wed, 6 Jun 2018 03:42:49 +0900 Subject: [PATCH 045/302] Created bogo_sort.py in algorithms/sort (#308) * Create bogo_sort.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_sort.py * Update __init__.py * Update test_sort.py * Update test_sort.py * Update bogo_sort.py * Update bogo_sort.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/bogo_sort.py | 22 ++++++++++++++++++++++ tests/test_sort.py | 5 +++++ 8 files changed, 33 insertions(+) create mode 100644 algorithms/sort/bogo_sort.py diff --git a/README.md b/README.md index c3fcb0aea..72aeaa230 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,7 @@ If you want to uninstall algorithms, it is as simple as: - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort](algorithms/sort) + - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) diff --git a/README_CN.md b/README_CN.md index e1a866f32..8683e6597 100644 --- a/README_CN.md +++ b/README_CN.md @@ -202,6 +202,7 @@ pip3 uninstall -y algorithms - [randomized_set:随机集合](algorithms/set/randomized_set.py) - [set_covering:集合覆盖](algorithms/set/set_covering.py) - [sort:排序](algorithms/sort) + - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort:梳排序](algorithms/sort/comb_sort.py) diff --git a/README_GE.md b/README_GE.md index 17cb14825..22c3703f4 100644 --- a/README_GE.md +++ b/README_GE.md @@ -227,6 +227,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort](algorithms/sort) + - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) diff --git a/README_JP.md b/README_JP.md index 043c4bcda..c9ba3ff2b 100644 --- a/README_JP.md +++ b/README_JP.md @@ -217,6 +217,7 @@ if __name__ == "__main__": - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort : ソート](algorithms/sort) + - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) diff --git a/README_KR.md b/README_KR.md index 45e2eafef..89f82926d 100644 --- a/README_KR.md +++ b/README_KR.md @@ -213,6 +213,7 @@ if __name__ == "__main__": - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort : 정렬 알고리즘](algorithms/sort) + - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index d86e2bce3..c7e0de2cb 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -1,3 +1,4 @@ +from .bogo_sort import * from .bubble_sort import * from .comb_sort import * from .counting_sort import * diff --git a/algorithms/sort/bogo_sort.py b/algorithms/sort/bogo_sort.py new file mode 100644 index 000000000..074a6afca --- /dev/null +++ b/algorithms/sort/bogo_sort.py @@ -0,0 +1,22 @@ +import random + +def bogo_sort(arr): + """Bogo Sort + Best Case Complexity: O(n) + Worst Case Complexity: O(∞) + Average Case Complexity: O(n(n-1)!) + """ + def is_sorted(arr): + #check the array is inorder + i = 0 + arr_len = len(arr) + while i+1 < arr_len: + if arr[i] > arr[i+1]: + return False + i += 1 + return True + while not is_sorted(arr): + random.shuffle(arr) + return arr + + diff --git a/tests/test_sort.py b/tests/test_sort.py index 4665259ab..adbb8f119 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -1,4 +1,5 @@ from algorithms.sort import ( + bogo_sort, bubble_sort, comb_sort, counting_sort, @@ -16,6 +17,10 @@ class TestSuite(unittest.TestCase): + def test_bogo_sort(self): + self.assertEqual([1, 5, 23], + bogo_sort([1, 23, 5])) + def test_bubble_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], bubble_sort([1, 5, 65, 23, 57, 1232])) From 1220a742917d37f2f9377bb22909c3a12deb47fd Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Wed, 6 Jun 2018 12:14:56 +0900 Subject: [PATCH 046/302] Fixed links in README files (#312) * Update README_CN.md * Update README.md * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README.md | 8 ++++---- README_CN.md | 8 ++++---- README_GE.md | 8 ++++---- README_JP.md | 10 +++++----- README_KR.md | 11 ++++++----- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 72aeaa230..9d9bb1291 100644 --- a/README.md +++ b/README.md @@ -62,11 +62,11 @@ If you want to uninstall algorithms, it is as simple as: - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) -    - [rotate_array](algorithms/arrays/rotate_array.py) - - [summary_ranges](algorithms/arrays/summary_ranges.py) +    - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) + - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [anagram](algorithms/backtrack/anagram.py) @@ -234,7 +234,7 @@ If you want to uninstall algorithms, it is as simple as: - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - - [topsort](algorithms/sort/topsort.py) + - [top_sort](algorithms/sort/top_sort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) - [stack](algorithms/stack) - [longest_abs_path](algorithms/stack/longest_abs_path.py) diff --git a/README_CN.md b/README_CN.md index 8683e6597..0461b107e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -75,11 +75,11 @@ pip3 uninstall -y algorithms - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) - [plus_one:加一运算](algorithms/arrays/plus_one.py) - - [rotate_array:反转数组](algorithms/arrays/rotate_array.py) - - [summary_ranges:数组范围](algorithms/arrays/summary_ranges.py) + - [rotate:反转数组](algorithms/arrays/rotate.py) + - [summarize_ranges:数组范围](algorithms/arrays/summarize_ranges.py) - [three_sum:三数和为零](algorithms/arrays/three_sum.py) - [two_sum:两数和](algorithms/arrays/two_sum.py) - - [move_zeros_to_end: 0后置问题](algorithms/arrays/move_zeros_to_end.py) + - [move_zeros: 0后置问题](algorithms/arrays/move_zeros.py) - [backtrack:回溯](algorithms/backtrack) - [general_solution.md:一般方法](algorithms/backtrack/) - [anagram:同字母异序词](algorithms/backtrack/anagram.py) @@ -216,7 +216,7 @@ pip3 uninstall -y algorithms - [selection_sort:选择排序](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors:颜色排序](algorithms/sort/sort_colors.py) - - [topsort:top排序](algorithms/sort/topsort.py) + - [top_sort:top排序](algorithms/sort/top_sort.py) - [wiggle_sort:摇摆排序](algorithms/sort/wiggle_sort.py) - [stack:栈](algorithms/stack) - [longest_abs_path:最长相对路径](algorithms/stack/longest_abs_path.py) diff --git a/README_GE.md b/README_GE.md index 22c3703f4..8aba1d043 100644 --- a/README_GE.md +++ b/README_GE.md @@ -69,11 +69,11 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) -    - [rotate_array](algorithms/arrays/rotate_array.py) - - [summary_ranges](algorithms/arrays/summary_ranges.py) +    - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) + - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [anagram](algorithms/backtrack/anagram.py) @@ -241,7 +241,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - - [topsort](algorithms/sort/topsort.py) + - [top_sort](algorithms/sort/top_sort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) - [stack](algorithms/stack) - [longest_abs_path](algorithms/stack/longest_abs_path.py) diff --git a/README_JP.md b/README_JP.md index c9ba3ff2b..ba06e6dd7 100644 --- a/README_JP.md +++ b/README_JP.md @@ -54,16 +54,16 @@ if __name__ == "__main__": - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus.py) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) - - [rotate_array](algorithms/arrays/rotate_array.py) - - [summary_ranges](algorithms/arrays/summary_ranges.py) +    - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) + - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack : バックトラッキング](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [anagram](algorithms/backtrack/anagram.py) @@ -231,7 +231,7 @@ if __name__ == "__main__": - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - - [topsort](algorithms/sort/topsort.py) + - [top_sort](algorithms/sort/top_sort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) - [stack : スタック](algorithms/stack) - [longest_abs_path](algorithms/stack/longest_abs_path.py) diff --git a/README_KR.md b/README_KR.md index 89f82926d..f5aee1ba1 100644 --- a/README_KR.md +++ b/README_KR.md @@ -52,16 +52,17 @@ if __name__ == "__main__": - [delete_nth](algorithms/arrays/delete_nth.py) - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus_problem.py) + - [josephus_problem](algorithms/arrays/josephus.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) - - [rotate_array](algorithms/arrays/rotate_array.py) - - [summary_ranges](algorithms/arrays/summary_ranges.py) +    - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros_to_end](algorithms/arrays/move_zeros_to_end.py) + - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack : 백트래킹](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [anagram](algorithms/backtrack/anagram.py) @@ -225,7 +226,7 @@ if __name__ == "__main__": - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) - - [topsort](algorithms/sort/topsort.py) + - [top_sort](algorithms/sort/top_sort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) - [stack : 스택](algorithms/stack) - [longest_abs_path](algorithms/stack/longest_abs_path.py) From 4c93de3eedc0f9e175ec4730092afa686615e619 Mon Sep 17 00:00:00 2001 From: Keon Date: Wed, 6 Jun 2018 03:05:47 -0400 Subject: [PATCH 047/302] Add documentation template (#314) * add docs template * add logo * create documentation template --- .gitignore | 2 + README.md | 2 + algorithms/__init__.py | 0 docs/Makefile | 20 +++ docs/make.bat | 36 +++++ docs/requirements.txt | 21 +++ docs/source/_static/algorithms_logo.png | Bin 0 -> 11878 bytes docs/source/arrays.rst | 16 +++ docs/source/backtrack.rst | 5 + docs/source/bfs.rst | 5 + docs/source/bit.rst | 5 + docs/source/conf.py | 177 ++++++++++++++++++++++++ docs/source/dfs.rst | 5 + docs/source/dp.rst | 5 + docs/source/examples.rst | 5 + docs/source/graph.rst | 5 + docs/source/heap.rst | 5 + docs/source/index.rst | 38 +++++ docs/source/linkedlist.rst | 5 + docs/source/map.rst | 5 + docs/source/maths.rst | 5 + docs/source/matrix.rst | 5 + docs/source/queues.rst | 5 + docs/source/search.rst | 5 + docs/source/set.rst | 5 + docs/source/sort.rst | 5 + docs/source/stack.rst | 5 + docs/source/strings.rst | 5 + docs/source/tree.rst | 5 + setup.py | 2 + 30 files changed, 409 insertions(+) create mode 100644 algorithms/__init__.py create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt create mode 100644 docs/source/_static/algorithms_logo.png create mode 100644 docs/source/arrays.rst create mode 100644 docs/source/backtrack.rst create mode 100644 docs/source/bfs.rst create mode 100644 docs/source/bit.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/dfs.rst create mode 100644 docs/source/dp.rst create mode 100644 docs/source/examples.rst create mode 100644 docs/source/graph.rst create mode 100644 docs/source/heap.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/linkedlist.rst create mode 100644 docs/source/map.rst create mode 100644 docs/source/maths.rst create mode 100644 docs/source/matrix.rst create mode 100644 docs/source/queues.rst create mode 100644 docs/source/search.rst create mode 100644 docs/source/set.rst create mode 100644 docs/source/sort.rst create mode 100644 docs/source/stack.rst create mode 100644 docs/source/strings.rst create mode 100644 docs/source/tree.rst diff --git a/.gitignore b/.gitignore index 86f7f584d..99f920b84 100755 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ __pycache__/ # Python egg metadata, regenerated from source files by setuptools. /*.egg-info /*.egg +# docs +build/ diff --git a/README.md b/README.md index 9d9bb1291..e9ddbb7be 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +

+ English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/algorithms/__init__.py b/algorithms/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..06f6415a1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = algorithms +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 000000000..a515cfe0d --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build +set SPHINXPROJ=algorithms + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 000000000..3f4e532f7 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,21 @@ +# Progress bars on iterators +tqdm +sphinx_rtd_theme + +# Downloading data and other files +requests + +# Required for tests only: + +# Style-checking for PEP8 +flake8 + +# Run unit tests +pytest + +# Lets pytest find our code by automatically modifying PYTHONPATH +pytest-pythonpath + +# Coverage statistics +pytest-cov +codecov diff --git a/docs/source/_static/algorithms_logo.png b/docs/source/_static/algorithms_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8487d9e7381397f77c36b2cc862cc286b4487c GIT binary patch literal 11878 zcmd6N_amEM^nVDoM^Jl)QnjiSwf7!1o0bwuQ58k)RY@tai_+GtQfenv(VDSKt(qyd z_l~N)zUlk(`Th@|^TYEbcbt39J@-E6-g92Dcg+nLXt`+t004uLp{^AG00fbK1>--;1K(4o|yQ zvYje7MDMs&4NQA%`A!dX!8Pc+9Z!7+)ZFsU@3*<3(Er!SFg&E4Q8P8*7Utg4jLN!d ztr(Gp7(VMc@LpFW*d7>4z5$2_Y~h1u-Dhc`+6{xoTeqO$Q1fVCd*lj=6=k6o$pQkc ztp`H>yxKqFgwzs0>4{|Ipd!e3fN9vp{1A=DKvA+Cvf6f9%p(7_&D=8)jOmCtI z3Z;?&xe|7=6%aL(~`1)^gf23P?8Q_=6gf3m*x&$^c5y4-m(73XRa>eef?CJ!8>^WUqDK z3Zu@klqmj?0umSQnPp9#^Bj9d}_aE5?77FsUtp683> zz~E~?H;vje@t^P1G|~_gvnSX=v0JxW6*V>xj5jB-Y9LUzWwjV66zH)ua&Q-#^Iro` zmceC0Za^hFNIb>W0z4)<(-AfaQ~4T)mjA#(G!hYoeZ*P^un~o!i3HNZD}4Vh4gC$GivONnB?M;qv38Uom~f@v|8dvkA$DS?(eb-pQ(?=J-In|<(kM$GEE=B~-C8dNz$q*r3h4XsjlMpT_I-4CLNl#

q0sFO z!}god<`sqJ}olV4PdfvvviU>#3b-%ffo3tA)R@LwBVtapO(b?F=1QDz>ab+aRut4pc(rFE`O|%DM;!!G z>IWMnw)4!c>$dV})tAyH2SDJ3=S#YVLuxt6(ShsNGUpe_|-tO-hj4rs0AOHFB z3r+?i<>PVH0}M+olLM7#q<>lRo}^ z3ibbXGy<~&?Yc@uTy_O!6MLGQ**SmQz}EsNng7+t7Tr%p!?7j0_tge|i@@k_UVC4W zj!Yq2iT@|4?x>_uJ2gTc9Pf@_HNQN+PIQ2(wqaBL^(1XW_h^xM2?E=P@?7A>=vs3g zW#<(=ib-;NDx46QL@au8A|MrVCt9UTzS(Z+%N^NPmRLu8$p2?PylT{b7g~ed>w<3x z)t%hNDS+GgQU5#gPf{g&x^P(_Dt>v_4UWViaWQ14SF&aPhjSHyY!ML-{h6@R-I=dT-_q9jo0<{C2|6$pK7<8pf&a#eR9V?uQ3Ps;O2!gy%sS8n(qiNShM%@PojAX7 zx!J~Hu&x|&2M1#k5rEU}Sd{Ng%#bHhT!Ab84%xqQP~gBMZvc0CJ*s9Oa_{1Pcw^aR zRapR(G2?FUCtlC=%cpJpcekl3zbl?W-JF}N?{M{R#fEcvIjsbX!I(mIkS|dv0!O%; z9C85JhCMup0M?HABn~6byA?i90gu=uC+bd+e~=n?IWP;??3E z2^+RW1Jd|td?3;jGvMyD**KCsAa-F}jb%jIZK^4-o<5ubW;<#&)F{zU*18*go{32Y zZufX^D?kk94b?A0?3!bg%S6wHu>))Lvud*;vvu_2{ZFhn)iC1hD`(R{K0@gGnqgVG zw`etu^U}Ake0{IumIEjbs_#X_jP6vc6MXgVZS|gSmp+%CczgOFk^F+jA=B&Vv!Ddr zYreee6L+PL?7{x@XN^gN!djg}GCV5;VU3MRewBxvSg ze)rcYTEDu4*sPYP*$8(RKHJ|8=`H_q4kF5X>k4VyKd%(tTnTGV^4NM|_ANVePMK-s z*!ShMn0iN(_r`5<9<|-)8drTDoo}l122FKg9EU=985)pNRYg>e&A?C#bBc?&eQ1{- zSfP&h&mOPU%I##T>2}9~cVy!^iBpHu6y_Cj(II?ozYjG%G1s?nOH7CX7Amhetzy6mr9lxk*#SBJs5@Z#+W@Zs9V2C+v%J zBQ@P0olQ~Dvx>f3jV#BLbV0lup53SW+uM)3o)Vk8iVQ!_bGJUP3?%WGic-r~bzB+n zzvJAzlH9EjhgBd#@&0iB`x^Cnq97-#>41xG^(xDX^Le$b81ZXDy8<=~HA!tvJ9{B~ zGX+qkV~Y7(`r|Qz^&zq0L?AY-B~T21h$v8s7a(5#+@g)d3tIM zRq;}pdgD%g`tqk}oXmkR{eqtK)DTmKcGu_JE`STNQsilxqGq- zbNnaxJ|mBK9V5?2x?LB^T9Z2? z%kY(+AXhy8o_(D8K(5zIWd8A4NTNX5-pY`n?zusnFennce>4B^V|kb4tUfd{p~{Rs zI9WIQWnvur`2+RHissUBD*|`%AQ$`nWQEOBkwR9H5m!Rv34Ffc%AQJP|4vtbktK(n zfbl`^x15vbmg8_2XtgxKLnudFBXM4Yv~BD*HIZAG!_L?djd4|f1DM)beHUZlm2+(V zYz3xIEP`K=_g)OtXpI&NOc{E>v=KJRV~-TjkwM6NT5j&$-}zEE;t(IM08i+wjJbA` z?%w>T4)1bEFMn9mE$5UF;N{D{!6WHkad)GXxHgc#3uiYn?1atTCfKrYskS`cS~)9G z>b%ml*&KxEx7C>Gk8CXH(iDPUDIuO(?coclWeFYfpT8auelL2IgoDD?&2?y^9@R=8 z3^obul3Kn*@?oNi%6HbZ2(SAiW79NkDxz&=%3N-&%oC{b>g^_ir6x;OA0 zm21rYkK0A&bz7Hh)l=uP)5t5S4)UjzFbvomR}9jYm7{7<&Fze>Eq4*QtF_m6-kdQb znl_}cKp&!#U97oCSsr{t@I-o5hP{yKVD@y2fO_P2ZR}fW>)vQ7q-)}ZLu|T=g^O8F zD?uJR=vMaNVR9n3l;z+)w?3`cGcS+f@QULHE+r4o80{)0+iyLl+F z*ML!hpk@f{Qf}d%OPZ|{)V}9lS#z}=$oY~@6^YDkqUqt3@5D@9IwMR~iXEDf)7yF#o zW52snAy(yTvY>$qouvx48x?Ol?jj=JS3J%>)n`K7=o-cXyH`Wy`**bCY6Wn`#=YW- zdvbtDw<5{sFA@g>YFi)(D%b$$!*GVI>38d)P|sP3JGcnZ1Fpev`2zjWxqvnt_rQ7) z(%0h`4^%6oEhO|~zy?g^eTJR};>{0#!^6(0(IH5B$>3*H$pe9-z)ivRzk=>tD50fY zA-fxYl1bXNB;l8_kr3p4h{4#QVZHE1i}YpVwK2N96W>{;@5M*GikKH{EQ0%r7HS7V z2sZLoei6rliy`#GM11tsj|!2PRHW>W78fjS05HB0jb-;BuLYKMF^ahHSSH2Xz#R5_ zb8lQobv*7;o{$#nRcR#&e-g-F^i%Ilx?7}4vJYgfUIoF(0rPD3%w8sB)QMqr&2(O$@&h7A`lt#Yy5S65`tN_o|Fb~a7;`*9e%9@4g<8o`S@ z95z+IY&N472(+(2r8G--`Hzp4Z?bwBV)Fu(j%5% zt~gtn(egA-NNp(DSw%iNi0_BCPLYi#Eh5=WASL)z99QPb@6_o zTz^a9btC10Ig>ap=ZI-nXS&Rpwvb2sCArIpt<+d-t!TjI-tH)mL-SsC zx9vc;3gNjbSXQh$tr%~cBt^HF*Y>=UU*SZU4C}X-_t0^+^ zX|EU65ak{AudEyHJ)ws^s)6O|G@*mL34sc@fK^EZD!|UfxoXdBvAS$kYEiB?!VKzA zfR*_AAG@b}IC!?9d)@2kh zWKA4a(C_larGKtWf&}rw<=U<2lKILw{C>x%6^v{=+N@sX`XMQK{IqOtr@v+Ue&{II z;mys9TN8H+KE1}cLwo#tYjlBXIPi}SYP!=J0c za}u{Q*0(b8Upt+3mTJzX4l&0ARG8Tk2_E?EA(@Ko(~+~w6OPy7v0r5c`x!|$m`7UJ z0I?mB`G=dn-0O-2`Ri3*)jO3L8PQM$Mm$UJcm~-oFP0cL^NDKss~~umxc+Tzqy^7|+V#uf;5UggY7f9ikT0x< zRG+=`O~_GO;`A67t`hlha&ygJHP<>jCufD%_i;+pw!;E1JkUU5j?S{GWN$|z_PTkl zQTrZY0w}{V_r~x`+5p>(Y8v{|Ct**z+*f$#)PM>{IHV~4+MLi>r8=LPWO4iB;LM?X zoRJ{ug0ogNF7Z*AI#eg2E1E$q`0sp3I9jLht?ro@)HEkK8GGkb@Q;mnjbsrR6XHC^ zAZ&}kJMkeKxkGLH{R@sH3a5Qwmp$ZN_Xly39FB*nE8pD~S|@iykHUpwj{X>eC$K{$ z)1{3+gZcBIDsMxTX-rJD;aQ1h40Jx!2M#POT|ktq{A>N|ps&8O$8hZ0-CW16&&$jP zArwPUg;w^b!H+wlx4itHcs<9p@~ihi?;)^3p8^oFt|>g%bCdVSg3@~>tQmISU~Z)~ z$MT_H_j8s%Fl!tpJi&4tgsZ40_B6z$c%`2;uTB z3n-10fluAlz4h95pVlA0K3w$}?KmoTe=Jm9x;l?qiL@ zCnIQO%`dD}LP|Tx!Y_9Mv*sF{pl!n!rA7?R(rP-aQ^BsseyU9Y?1V|5?`+b2!*=UF~VowIDB&~LKE>Zwq!trr9A`xee>quAd`>Cer6#xZ&} zP-o8%ntw{emc-?sq|Go#d=eWx*ZTaUx~oAVIsC0)n0lz=GF14t%vJ9SRsMs+f&9M8 zevvb>CMJwF{&=*NM`(;uwK@Owo!BEa=QgW~MeD%2>cLwnK;qPTV{g*4#|sR9c0BLD z^1w`CtbJeV@GPJ&PXYpN&lP~eyK!rF)5=H>IF-=H+w2=$(nHr{6s)FNY7=2M&Rc$m zGd3)K<1Z>3Tx$r&_PJJPY92lQ9*kO1e0@s{qykhU?-ximYy3XU6(vLDrPy3%Hu<%+ zI@qZ~_)tsWCsR-0)8zNaEF^VVb+g{k&DvNzZxS1KNAJ(uc|sP( z|5Y&8z1f=Sj@neal#QlsCe>z2P8RPAo~QxlUyMf&pgar(Z=)|o_4xbo#&=>? zEgl%Po8TLBTh)dq@WqY zmQ_}qC2!uwB$DAnNM4YO=}azw+3LX#*=3yfRCm-)_ek1b_!7S=74@tIb9?aD#N)q1MJ zvU|Ie_wS5+j=JVv-R;(VRVJAtcZTkizGxQy=ht`ROoMXEK?|Cyw`1BzBX(Y1dS6{v zS8oswEmr+DIJKL~@TIB24bP!j<6AF0$&cKM6-+*o#x#zqhdv>V`?}VXCGSn!f z`v&%x-B$3v;3Vt!Zes!$#s*OjuLU`c>s(hs;U8 zGxjCdx!Z3vuE{zMaHR{k+k}NKZhU)+s92ogk^@LkhSK4l&chJRWo*g?ze(Pk@REqw zHk3!}t z)7eP$xP=RCaq%F-$mdnTFs(p|Vdk6Fkf>SpjR*YNi z!K)RtQ>zksj`4o+>>eVjFF`>V#--}(0Sn`L7{=WK)C{@et8MAc+v3(NSVre~9{X5p zz5MkXVMXD*vxE91WeD1JjPp_=l957DGB&23jYfgm9DWDj3-fQ)hE+D$*Ctdx0*mn1 zI(_yxKGtod_dE_Ved9cu8D}bjFH-gdY$o@;CPHdC^hhDsEo!H&iyK6Yj-*g0^K&2* zU!r)HR+QVi%c^*CM}Y&(xZZ2PWc5Wq`}}xuUL*@FWu$PZ+ObOCboH|mD^Cg_LvXi8NTNDxX+XLD^|fP z-|257>ZKYv&0tdaPg00CFCNv18V5gYmcfO$$UVj@lFyYHCcnw)(iwx-^C=%4bMvYoxudp~)Ut?moB8rF_jN@g z3Xq9d%UH2k#cLtqvkr)YC6RQY*rO-2$E+xOHFBR@to9rrWe401g}4srR9v;a_eUxro*gFY9jzl7{PjnE zVh2({=}X$@0p1BnOFn~_39GurOj}UvI9l4IZK90J&+-+h6(M~t0hfFB27J605ZON~10r~LRllrIPVjv#oi&y^dNa}De z40g`rlNh%OpGeLLbo#53``}pA>-A!|^@3PZLXJn;cqhJZ&}sc+h=4|v!{%NRmi^Ow zzxL1F`SQ-F)Tq51{|c|*3S3cXPc4=pDR`C8m!D(PXc81V#wPHLDy6e^J(L)%sg5UE zB8u@6XW4tV291`FPQ%bPv5*3cCBe&90{;$8&6Qsg-yBLS5nSKt-sw>=l2WGu+4l*rS_5v zL2*&gm1qSliRYRq0lNXB?f;oYq(>_pOSX(U?a#G2E<#o(ZUl z%TdC+R!0&H9?E8H9Xm-1cp?*<^phB3HuOxXt78|L=$6+H^=U1XExOhx63!LjgcE*A1#81}$ z%?&oKN7V3 z+JsXcf|Q2x`DBX8<0){mtV&%%?C$hZcsxN1ZCH{+AI7Od%~Wy?B#gP!D>MzBY7|;_ zk)LDg2B@ffN%=6NTvHA9F%ZUGOA-41)L~<=^D|zNcVhP$U@o*TEWvh+nT%)DibV*V zzb#e{vt~j(@v{-X2KoVKx}Sdm{Jl14o|4;Ibo=E*SAHT}BduxRV>e2uS8Hf-wK5w- zWvGT@QJ&-`$;#umrnx4+9hvgfcjhy=^M)g@!Kj459}lmq>%l)5i^r;nz9=NY6N>&} z0U%V9Q0aF1a*@ZsekW}4@;g& zR27zip_ntWj(Z+;34e>V95zS#OY!2Q6QIXUq8apd4DPA#V;$}v%!t}xPztjNbJN_W z1V1XuP&`(Nke|r3EB=nVEst1oy{1x!6tw2b6QM&q7-k^#pXVAX`#zFmzdLE;NjF2@qf*)ne8adPMz=^`)##L5yg>+Y|w zQW;_xz3luGC{L#R2OhpjZX;Qm71qLfkbU6ADq&2TtzLai49|q6RnD)>=dGVM3D-W< zAuFpqFpCM$Eri$u4*?o+eAF0L=Si-p%3|*nW0qaI7==z)yv~nJWvDikM+!gA3p4tu zL#X4BQGqiZXDQ?E*QgM|OA_^=YE4WRqvOu^x)kak2xM&^_!b}N10#H%m<-KZ+WAm! zl47l!L1y$S?YW7>N=erA@KG!JE4Q1i+el)T@Vy;pCx@27W zh0SmBO{&cu!g42m2UUhNp`HP_D&f3CWqQ6H&*;u-L0O?j#R>+1d+_GwNo=@=Dm@uv zR};0qa?KsqEakvj>(JB;i=2sHJR4^xKGD80FzXLr=;{nrvtTnkq41aX(vqunF>s#h zX!eV*(?S_gaS_nH1-Wx5!>mY50Cx+R5E)Q#4YY-CMr~0K%&XW_hVCGe)n;9PIUufk zlOGTpg~lc=?Kqrc&rzCA#R_j)Q_G}~E7*OG`=O`z+EW+JuyIfG6&Few%Wp=GH;JU? zcAIbgrAlhuuIU=_nYJVt?owWlWsa?oIVk@kWoJp$ARNvdWmg6=9vlmB6U-&X#5o?) z8nxRMf((S+Tll|>740^ClI~O|hJqY_y|327zrk9yQ9-RAY*+BYSA6;v(tQ=$QZv&_ zD#(X>jkA70nS{kpoXTH}iXJugH)3-0Km?C~TR7Q89YWjbS&!UK)RY9SGc|e%Yiyd^ z3H1<~e)ja*)szDS?|fz45O=y3gL_lTy8*B# z*XUrs>0iLk&&hG1&KfC^GeOI)5__aPmL+^~1={GCxEg?v zYGeBDb+|SSxiz=NIvWU~u^dQwt$M~4zpLL`YS?SxbXH{QGRm0EbavwzZ)$TO)>7Z= z+^AMZQ+IthZJ>(Afi>%Vuzy7bP@3bI)BK~1&#AH7Epc05*Zv--q^o~X;`bFHv*ia| zJo;X`#jw$dZX0pZG^p z;`=YXK;^88$va08se}tX*)((;${AEOLvPo*yro$B5cvj1Wf|j!3Wrmrw6qbx8#n?= zDeI-#FJ-v^L90(ckj13iI@l_v7IQoFXJE;;q$>+nnfpSj^=6pyYSEL2Jy_-g|Fgq{ z>(7)&1Ta7Ij3^!DEYh(2IjnFhu%#+0U5*`OG(|;tFz5m9+NH#%qHDwl{E|M~lb1aj z{vOa?dRDk@hR9E^9aNKA_gBZ|Po9-tPj7*gw->RXm-p#rL5R3~v|;HqrL@>j@mf;< zTYYdZiiZ-@@|i#JyAaBkBMsENG3n`l+2It+;Btp4o!2{L<$U%AzM`?yuRh*=b2rJ- z6y$C`0OfNm?qYo82s3wM+4U2{{hDkx5_1osh%c$1N>(f7t06^SI`#{|Cl%I_I0K1b-zFZ_em`1$YiFC$2I=RoBc)cJO2CImikwX+3hXU4B@IenUVtO>l)ygn<;J z=c9eD17}t4Q}5>)do`WpGgQ$)fidrX&CPvxwq$5*yC^|Eg=X}GxepC|`EaEWQaZ=?XH>$ZvmPI@H zD_s4uL;2DH$_2HU6-Vri51{2JL-dzUssJ(0>GCFNsx}?m6Yd>18t8>`a)0QLu$Ixk zu8A8^DtA+h=O;KUK=uyGq$_xfVTwr~FDRQ5RQjHqO9L+E5W7<-smJwz`c!?R z-vEDoQ|;}?z!0JNa=O#En6IHJ7TDwm4XE>r>h_1>Ofhw3&yZJXf004BPt6@Ec;5XT z>-@b_Hh>hv`oFxNhfRGiWb3YA4`ae@z&2P)>+dp_o*imGytt6u1ZrG8{c}QZl91cU ze>5ldQCp+_>F%Jg?@?egIIYcxGC0c4)e3 zLIff5zbFffFm*w*9x!%JSI0wlCQ*dbuY0F8Ip2212QW#|?u2ug{K4Qe6H8RQ;nV>+ zu2Y#g1fI9sLsjuwjIN8P$!evxP6Yz@^@OEezOcUYO~o4 zyvbjG>}vK~R~tc*fY%4TY1bb=vAsYr9$;<)>)lN83U9++bpCp8S@=tmtQ;sAV;0FB zm1rf|%fT9Jw`^{i85Qo-__C==xBb^MLM}TWS&BcJb*9h=o2nnv3x& z>6rY-l10d>fe+~doD3p`J^sO$Bwy>I*}ORCc;*uKssF=K(UAaz9TPc3OSHvLm>H=} ztf5hqAr?nIMvYkD3VY)64;1z2gNSyal7#bqaebNW!{mFPJntd?v2!3fUh)1U`~l-u z*z905sih$amZclFXZHRclt%_0YDy|16-KJ0WBQg#y9DAH9sZ4~8&|7%GmA(8yWt(s zg8dJ6B_HLCuheWNphjjjq4Mel%ob$AaSZ=qy$WR$0NVimD~yS}KhAhx+FJcF6m$iQ zU*-89VA%ra71d-lhh$2Aim^oQpB(3$oWL&&X}S#zh=;2dg8#5nLz>afJe9Trm=)-$ z=x?U-tFo1)8>j)I5r1g`^Emqn>wjX(zpXUVU4gUX0-!t8KH)q^oXtOD)@7T%3y{E+ zB%~UsPbPNtLEow|!e>tbueqW$Mt(r?JT@^ZNR%7?;NJ&mE;$kD*u^%n`9@WACG1a@fIX6M50?VBr^@|ij%JX4x5_) zv|BdtAeG!?S7QHqJK(=bqaztzr1Bm9I&|va*Pi4^jfdYACX_DS`>{ycSV0l+{P0|}n0E0U%E zmId7BNe9(|h9d%3uFXdeSB#@3v4wM;-?9JkH53a+@get6wP+QWHNIJGXqIXO^xvA} zlxGo2d}>}IeuAO_u#zaalT_dk{u(Km{c zFR;a|S+t>+kR3O=08qg^nQ&FQ$CO3ROAs-#1*9zAgFx<1;{Sh^cK<}^*mks|TVq{F QKyiSPp1E$NHuS~+175wD=Kufz literal 0 HcmV?d00001 diff --git a/docs/source/arrays.rst b/docs/source/arrays.rst new file mode 100644 index 000000000..5e5623f5c --- /dev/null +++ b/docs/source/arrays.rst @@ -0,0 +1,16 @@ +.. role:: hidden + :class: hidden-section + +algorithms.arrays +================= + +.. automodule:: algorithms.arrays +.. currentmodule:: algorithms.arrays + +longest_non_repeat +------------------ + +:hidden:`longest_non_repeat_v1` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: longest_non_repeat_v1 diff --git a/docs/source/backtrack.rst b/docs/source/backtrack.rst new file mode 100644 index 000000000..0c33a3316 --- /dev/null +++ b/docs/source/backtrack.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.backtrack +==================== diff --git a/docs/source/bfs.rst b/docs/source/bfs.rst new file mode 100644 index 000000000..699b9e925 --- /dev/null +++ b/docs/source/bfs.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.bfs +================= diff --git a/docs/source/bit.rst b/docs/source/bit.rst new file mode 100644 index 000000000..b7aa877c0 --- /dev/null +++ b/docs/source/bit.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.bit +================= diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 000000000..b6c0c8320 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# algorithms documentation build configuration file, created by +# sphinx-quickstart on Wed Jun 6 01:17:26 2018. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) +from recommonmark.parser import CommonMarkParser + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_parsers = { + '.md': CommonMarkParser +} +source_suffix = ['.rst', '.md'] + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'algorithms' +copyright = '2018, Algorithms Team & Contributors' +author = 'Algorithms Team & Contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1.0' +# The full version, including alpha/beta/rc tags. +release = '0.1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'about.html', + 'searchbox.html', + 'navigation.html', + 'relations.html', # needs 'show_related': True theme option to display + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'algorithmsdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'algorithms.tex', 'algorithms Documentation', + 'Algorithms Team \\& Contributors', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'algorithms', 'algorithms Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'algorithms', 'algorithms Documentation', + author, 'algorithms', 'One line description of project.', + 'Miscellaneous'), +] diff --git a/docs/source/dfs.rst b/docs/source/dfs.rst new file mode 100644 index 000000000..1d2c5b6de --- /dev/null +++ b/docs/source/dfs.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.dfs +================= diff --git a/docs/source/dp.rst b/docs/source/dp.rst new file mode 100644 index 000000000..1cc92081e --- /dev/null +++ b/docs/source/dp.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.dp +================= diff --git a/docs/source/examples.rst b/docs/source/examples.rst new file mode 100644 index 000000000..5d3cbdd76 --- /dev/null +++ b/docs/source/examples.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +Examples +================= diff --git a/docs/source/graph.rst b/docs/source/graph.rst new file mode 100644 index 000000000..925d10524 --- /dev/null +++ b/docs/source/graph.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.graph +================= diff --git a/docs/source/heap.rst b/docs/source/heap.rst new file mode 100644 index 000000000..068578a3e --- /dev/null +++ b/docs/source/heap.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.heap +================= diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 000000000..d751ceea4 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,38 @@ +.. image:: /_static/algorithms_logo.png + :target: https://github.com/keon/algorithms + :scale: 50 % + +The :mod:`algorithms` package consists of +minimal and clean example implementations of data structures and algorithms. + +.. toctree:: + :maxdepth: 2 + :caption: Package Reference + + self + algorithms.arrays + algorithms.backtrack + algorithms.bfs + algorithms.bit + algorithms.dfs + algorithms.dp + algorithms.graph + algorithms.heap + algorithms.linkedlist + algorithms.map + algorithms.maths + algorithms.matrix + algorithms.queues + algorithms.search + algorithms.set + algorithms.sort + algorithms.stack + algorithms.strings + algorithms.tree + examples + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` diff --git a/docs/source/linkedlist.rst b/docs/source/linkedlist.rst new file mode 100644 index 000000000..4a37b37e5 --- /dev/null +++ b/docs/source/linkedlist.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.linkedlist +===================== diff --git a/docs/source/map.rst b/docs/source/map.rst new file mode 100644 index 000000000..31d281f85 --- /dev/null +++ b/docs/source/map.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.map +================= diff --git a/docs/source/maths.rst b/docs/source/maths.rst new file mode 100644 index 000000000..1a45b7957 --- /dev/null +++ b/docs/source/maths.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.maths +================= diff --git a/docs/source/matrix.rst b/docs/source/matrix.rst new file mode 100644 index 000000000..4d06e70a4 --- /dev/null +++ b/docs/source/matrix.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.matrix +================= diff --git a/docs/source/queues.rst b/docs/source/queues.rst new file mode 100644 index 000000000..3ee9e18a7 --- /dev/null +++ b/docs/source/queues.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.queue +================= diff --git a/docs/source/search.rst b/docs/source/search.rst new file mode 100644 index 000000000..091f0bf05 --- /dev/null +++ b/docs/source/search.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.search +================= diff --git a/docs/source/set.rst b/docs/source/set.rst new file mode 100644 index 000000000..80984858b --- /dev/null +++ b/docs/source/set.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.set +================= diff --git a/docs/source/sort.rst b/docs/source/sort.rst new file mode 100644 index 000000000..0b106e37b --- /dev/null +++ b/docs/source/sort.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.sort +================= diff --git a/docs/source/stack.rst b/docs/source/stack.rst new file mode 100644 index 000000000..ad1f76525 --- /dev/null +++ b/docs/source/stack.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.stack +================= diff --git a/docs/source/strings.rst b/docs/source/strings.rst new file mode 100644 index 000000000..708df2a0b --- /dev/null +++ b/docs/source/strings.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.string +================= diff --git a/docs/source/tree.rst b/docs/source/tree.rst new file mode 100644 index 000000000..1dea821b4 --- /dev/null +++ b/docs/source/tree.rst @@ -0,0 +1,5 @@ +.. role:: hidden + :class: hidden-section + +algorithms.tree +================= diff --git a/setup.py b/setup.py index b7374e85c..1bb71d3b6 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,6 @@ import os +import io +import re from setuptools import find_packages, setup setup(name='algorithms', From 43ccd21b7087b6df47c468727c390e67cf1f2172 Mon Sep 17 00:00:00 2001 From: ppuzzle Date: Wed, 6 Jun 2018 17:08:12 +0900 Subject: [PATCH 048/302] Added link to OS Helpers, Build Status, and Coverage Status in README files. (#316) * Update README_CN.md * Update README_JP.md * Update README_KR.md --- README_CN.md | 4 ++++ README_JP.md | 4 ++++ README_KR.md | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/README_CN.md b/README_CN.md index 0461b107e..683830cd4 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,5 +1,9 @@ [English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + Python版数据结构和算法 ========================================= diff --git a/README_JP.md b/README_JP.md index ba06e6dd7..8e18adcb1 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,5 +1,9 @@ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) +[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + Pythonのデータ構造とアルゴリズム ========================================= diff --git a/README_KR.md b/README_KR.md index f5aee1ba1..08d41dccb 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,5 +1,9 @@ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) +[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + Python 버전 자료구조 및 알고리즘 ========================================= From 6b662a108196b09c25fdc1ef27a553296b917cb0 Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Wed, 6 Jun 2018 14:52:59 +0530 Subject: [PATCH 049/302] Created PULL_REQUEST_TEMPLATE.md (#311) * Create PULL_REQUEST_TEMPLATE.md * review change --- PULL_REQUEST_TEMPLATE.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..3de1ba41a --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +(Put an `X` inside the `[ ]` to denote check mark `[X]`.) + + +- [ ] **If creating a new file :** + - [ ] added links to it in the README files ? + - [ ] included tests with it ? + - [ ] added description (overview of algorithm, time and space compleixty, and possible edge case) in docstrings ? + +- [ ] **if done some changes :** + - [ ] wrote short description in the PR explaining what the changes do ? + - [ ] Fixes #[issue number] if related to any issue + +- [ ] **other** From d0464ccc31ffdf782eb176af7e03c4864d92d251 Mon Sep 17 00:00:00 2001 From: hsi1032 Date: Wed, 6 Jun 2018 18:24:49 +0900 Subject: [PATCH 050/302] Create cocktail_shaker_sort and add test case (#310) * Create cocktail_shaker_sort.py * Update __init__.py * Update test_sort.py * Update test_sort.py * Update README.md * Update README_CN.md * Update README_CN.md * Update README.md * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/cocktail_shaker_sort.py | 30 +++++++++++++++++++++++++ tests/test_sort.py | 8 +++++-- 8 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 algorithms/sort/cocktail_shaker_sort.py diff --git a/README.md b/README.md index e9ddbb7be..bdfc343aa 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,7 @@ If you want to uninstall algorithms, it is as simple as: - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) diff --git a/README_CN.md b/README_CN.md index 683830cd4..7f0abeaa6 100644 --- a/README_CN.md +++ b/README_CN.md @@ -209,6 +209,7 @@ pip3 uninstall -y algorithms - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort:梳排序](algorithms/sort/comb_sort.py) - [counting_sort:计数排序](algorithms/sort/counting_sort.py) - [heap_sort:堆排序](algorithms/sort/heap_sort.py) diff --git a/README_GE.md b/README_GE.md index 8aba1d043..f4de311a1 100644 --- a/README_GE.md +++ b/README_GE.md @@ -230,6 +230,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) diff --git a/README_JP.md b/README_JP.md index 8e18adcb1..1abcebe75 100644 --- a/README_JP.md +++ b/README_JP.md @@ -224,6 +224,7 @@ if __name__ == "__main__": - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) diff --git a/README_KR.md b/README_KR.md index 08d41dccb..796af776d 100644 --- a/README_KR.md +++ b/README_KR.md @@ -220,6 +220,7 @@ if __name__ == "__main__": - [sort : 정렬 알고리즘](algorithms/sort) - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index c7e0de2cb..27468e8e2 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -11,3 +11,4 @@ from .bucket_sort import * from .shell_sort import * from .radix_sort import * +from .cocktail_shaker_sort import * diff --git a/algorithms/sort/cocktail_shaker_sort.py b/algorithms/sort/cocktail_shaker_sort.py new file mode 100644 index 000000000..973b824b6 --- /dev/null +++ b/algorithms/sort/cocktail_shaker_sort.py @@ -0,0 +1,30 @@ +def cocktail_shaker_sort(arr): + """ + Cocktail_shaker_sort + Sorting a given array + mutation of bubble sort + + reference: https://en.wikipedia.org/wiki/Cocktail_shaker_sort + + Worst-case performance: O(N^2) + """ + + def swap(i, j): + arr[i], arr[j] = arr[j], arr[i] + + n = len(arr) + swapped = True + while swapped: + swapped = False + for i in range(1, n): + if arr[i - 1] > arr[i]: + swap(i - 1, i) + swapped = True + if swapped == False: + return arr + swapped = False + for i in range(n-1,0,-1): + if arr[i - 1] > arr[i]: + swap(i - 1, i) + swapped = True + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index adbb8f119..ef8e75463 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -10,7 +10,8 @@ selection_sort, bucket_sort, shell_sort, - radix_sort + radix_sort, + cocktail_shaker_sort ) import unittest @@ -68,7 +69,10 @@ def test_shell_sort(self): def test_radix_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], radix_sort([1, 5, 65, 23, 57, 1232])) - + + def test_cocktail_shaker_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + cocktail_shaker_sort([1, 5, 65, 23, 57, 1232])) if __name__ == "__main__": From 537e4fb48557dd73a87e9cba88be30195b6a1e79 Mon Sep 17 00:00:00 2001 From: Keon Date: Wed, 6 Jun 2018 05:37:53 -0400 Subject: [PATCH 051/302] add to python package index (#320) --- README.md | 2 +- setup.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bdfc343aa..173ed9f37 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ For running all tests write down: ## Install If you want to use the API algorithms in your code, it is as simple as: - $ pip3 install git+https://github.com/keon/algorithms + $ pip3 install algorithms You can test by creating a python file: (Ex: use `merge_sort` in `sort`) diff --git a/setup.py b/setup.py index 1bb71d3b6..65a80c638 100644 --- a/setup.py +++ b/setup.py @@ -3,16 +3,26 @@ import re from setuptools import find_packages, setup + +def long_description(): + with io.open('README.md', 'r', encoding='utf-8') as f: + readme = f.read() + return readme + + setup(name='algorithms', - version='1.1', + version='0.1.0', description='Pythonic Data Structures and Algorithms', + long_description=long_description(), url='https://github.com/keon/algorithms', - author='Keon Kim, Hai Hoang Dang, Rahul Goswami, Christian Bender, Saad', + author='Algorithms Team & Contributors', + author_email="kwk236@gmail.com", license='MIT', packages=find_packages(), classifiers=[ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', ], zip_safe=False) From 36c1af414476804938b36c743b45bb750e5fbc16 Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Wed, 6 Jun 2018 18:38:36 +0900 Subject: [PATCH 052/302] Created gnome sort in sort algorithm (#313) * Create gnome_sort.py * Update __init__.py * Update test_sort.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update gnome_sort.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/gnome_sort.py | 19 +++++++++++++++++++ tests/test_sort.py | 9 +++++++-- 8 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 algorithms/sort/gnome_sort.py diff --git a/README.md b/README.md index 173ed9f37..f31075f57 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ If you want to uninstall algorithms, it is as simple as: - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) diff --git a/README_CN.md b/README_CN.md index 7f0abeaa6..4e938223e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -212,6 +212,7 @@ pip3 uninstall -y algorithms - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort:梳排序](algorithms/sort/comb_sort.py) - [counting_sort:计数排序](algorithms/sort/counting_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort:堆排序](algorithms/sort/heap_sort.py) - [insertion_sort:插入排序](algorithms/sort/insertion_sort.py) - [meeting_rooms:会议室](algorithms/sort/meeting_rooms.py) diff --git a/README_GE.md b/README_GE.md index f4de311a1..8bc1fd2a5 100644 --- a/README_GE.md +++ b/README_GE.md @@ -233,6 +233,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) diff --git a/README_JP.md b/README_JP.md index 1abcebe75..0e63b9c09 100644 --- a/README_JP.md +++ b/README_JP.md @@ -227,6 +227,7 @@ if __name__ == "__main__": - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) diff --git a/README_KR.md b/README_KR.md index 796af776d..fde2147b7 100644 --- a/README_KR.md +++ b/README_KR.md @@ -223,6 +223,7 @@ if __name__ == "__main__": - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index 27468e8e2..a2c6d3c6f 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -11,4 +11,5 @@ from .bucket_sort import * from .shell_sort import * from .radix_sort import * +from .gnome_sort import * from .cocktail_shaker_sort import * diff --git a/algorithms/sort/gnome_sort.py b/algorithms/sort/gnome_sort.py new file mode 100644 index 000000000..aaf38a278 --- /dev/null +++ b/algorithms/sort/gnome_sort.py @@ -0,0 +1,19 @@ +""" + +Gnome Sort +Best case performance is O(n) +Worst case performance is O(n^2) + +""" + + +def gnome_sort(arr): + n = len(arr) + index = 0 + while index < n: + if index == 0 or arr[index] >= arr[index-1]: + index = index + 1 + else: + arr[index], arr[index-1] = arr[index-1], arr[index] + index = index - 1 + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index ef8e75463..020b9a343 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -11,7 +11,8 @@ bucket_sort, shell_sort, radix_sort, - cocktail_shaker_sort + gnome_sort, + cocktail_shaker_sort, ) import unittest @@ -69,7 +70,11 @@ def test_shell_sort(self): def test_radix_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], radix_sort([1, 5, 65, 23, 57, 1232])) - + + def test_gnome_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + gnome_sort([1, 5, 65, 23, 57, 1232])) + def test_cocktail_shaker_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], cocktail_shaker_sort([1, 5, 65, 23, 57, 1232])) From f6aa8d6a47f145bfb7a1b5b1bac38ee859238455 Mon Sep 17 00:00:00 2001 From: Keon Date: Wed, 6 Jun 2018 06:12:10 -0400 Subject: [PATCH 053/302] clean up backtrack and move tests to test_backtest (#306) * clean up backtrack and add tests * fix typos in backtrack --- algorithms/backtrack/__init__.py | 15 ++ algorithms/backtrack/add_operators.py | 45 +++++ algorithms/backtrack/anagram.py | 49 ----- .../backtrack/array_sum_combinations.py | 142 +++++++-------- algorithms/backtrack/combination_sum.py | 24 +-- .../backtrack/expression_add_operators.py | 54 ------ algorithms/backtrack/factor_combinations.py | 5 +- algorithms/backtrack/find_words.py | 73 ++++++++ algorithms/backtrack/general_solution.md | 156 ---------------- .../backtrack/generate_abbreviations.py | 30 ++-- algorithms/backtrack/generate_parenthesis.py | 25 ++- algorithms/backtrack/letter_combination.py | 7 +- .../backtrack/palindrome_partitioning.py | 28 ++- algorithms/backtrack/pattern_match.py | 44 ++--- algorithms/backtrack/permute.py | 90 ++++++---- algorithms/backtrack/permute_unique.py | 27 +-- algorithms/backtrack/subsets.py | 79 ++++---- algorithms/backtrack/subsets_unique.py | 56 +++--- algorithms/backtrack/word_search.py | 111 ------------ tests/test_backtrack.py | 170 ++++++++++++++++++ 20 files changed, 585 insertions(+), 645 deletions(-) create mode 100644 algorithms/backtrack/__init__.py create mode 100644 algorithms/backtrack/add_operators.py delete mode 100644 algorithms/backtrack/expression_add_operators.py create mode 100644 algorithms/backtrack/find_words.py delete mode 100644 algorithms/backtrack/general_solution.md delete mode 100644 algorithms/backtrack/word_search.py create mode 100644 tests/test_backtrack.py diff --git a/algorithms/backtrack/__init__.py b/algorithms/backtrack/__init__.py new file mode 100644 index 000000000..f8cdab753 --- /dev/null +++ b/algorithms/backtrack/__init__.py @@ -0,0 +1,15 @@ +from .add_operators import * +from .anagram import * +from .array_sum_combinations import * +from .combination_sum import * +from .factor_combinations import * +from .find_words import * +from .generate_abbreviations import * +from .generate_parenthesis import * +from .letter_combination import * +from .palindrome_partitioning import * +from .pattern_match import * +from .permute_unique import * +from .permute import * +from .subsets_unique import * +from .subsets import * diff --git a/algorithms/backtrack/add_operators.py b/algorithms/backtrack/add_operators.py new file mode 100644 index 000000000..7a847396c --- /dev/null +++ b/algorithms/backtrack/add_operators.py @@ -0,0 +1,45 @@ +""" +Given a string that contains only digits 0-9 and a target value, +return all possibilities to add binary operators (not unary) +, -, or * +between the digits so they prevuate to the target value. + +Examples: +"123", 6 -> ["1+2+3", "1*2*3"] +"232", 8 -> ["2*3+2", "2+3*2"] +"105", 5 -> ["1*0+5","10-5"] +"00", 0 -> ["0+0", "0-0", "0*0"] +"3456237490", 9191 -> [] +""" + + +def add_operators(num, target): + """ + :type num: str + :type target: int + :rtype: List[str] + """ + + def dfs(res, path, num, target, pos, prev, multed): + if pos == len(num): + if target == prev: + res.append(path) + return + for i in range(pos, len(num)): + if i != pos and num[pos] == '0': # all digits have to be used + break + cur = int(num[pos:i+1]) + if pos == 0: + dfs(res, path + str(cur), num, target, i+1, cur, cur) + else: + dfs(res, path + "+" + str(cur), num, target, + i+1, prev + cur, cur) + dfs(res, path + "-" + str(cur), num, target, + i+1, prev - cur, -cur) + dfs(res, path + "*" + str(cur), num, target, + i+1, prev - multed + multed * cur, multed * cur) + + res = [] + if not num: + return res + dfs(res, "", num, target, 0, 0, 0) + return res diff --git a/algorithms/backtrack/anagram.py b/algorithms/backtrack/anagram.py index 862140fc1..7c807cdbd 100644 --- a/algorithms/backtrack/anagram.py +++ b/algorithms/backtrack/anagram.py @@ -1,31 +1,3 @@ -import unittest - -def all_perms_iter(elements): - """ - iterator: returns a perumation by each call. - """ - if len(elements) <=1: - yield elements - else: - for perm in all_perms_iter(elements[1:]): - for i in range(len(elements)): - yield perm[:i] + elements[0:1] + perm[i:] - - -def all_perms(elements): - """ - returns a list with the permuations. - """ - if len(elements) <=1: - return elements - else: - tmp = [] - for perm in all_perms(elements[1:]): - for i in range(len(elements)): - tmp.append(perm[:i] + elements[0:1] + perm[i:]) - return tmp - - def anagram(s1, s2): c1 = [0] * 26 c2 = [0] * 26 @@ -39,24 +11,3 @@ def anagram(s1, s2): c2[pos] = c2[pos] + 1 return c1 == c2 - - -class TestSuite (unittest.TestCase): - - def test_all_perms(self): - perms = ['abc', 'bac', 'bca', 'acb', 'cab', 'cba'] - self.assertEqual(perms, all_perms("abc")) - - def test_all_perms_iter(self): - it = all_perms_iter("abc") - perms = ['abc', 'bac', 'bca', 'acb', 'cab', 'cba'] - for i in range(len(perms)): - self.assertEqual(perms[i], next(it)) - - def test_angram(self): - self.assertTrue(anagram('apple', 'pleap')) - self.assertFalse(anagram("apple", "cherry")) - - -if __name__ == "__main__": - unittest.main() diff --git a/algorithms/backtrack/array_sum_combinations.py b/algorithms/backtrack/array_sum_combinations.py index b8dbc8046..b152e4d11 100644 --- a/algorithms/backtrack/array_sum_combinations.py +++ b/algorithms/backtrack/array_sum_combinations.py @@ -5,7 +5,7 @@ /* A = [1, 2, 3, 3] B = [2, 3, 3, 4] -C = [1, 2, 2, 2] +C = [2, 3, 3, 4] target = 7 */ @@ -16,79 +16,69 @@ import itertools from functools import partial -A = [1, 2, 3, 3] -B = [2, 3, 3, 4] -C = [1, 2, 2, 2] -target = 7 - - -def construct_candidates(constructed_sofar): - global A, B, C - array = A - if 1 == len(constructed_sofar): - array = B - elif 2 == len(constructed_sofar): - array = C - return array - - -def over(constructed_sofar): - global target - sum = 0 - to_stop, reached_target = False, False - for elem in constructed_sofar: - sum += elem - if sum >= target or len(constructed_sofar) >= 3: - to_stop = True - if sum == target and 3 == len(constructed_sofar): - reached_target = True - - return to_stop, reached_target - - -def backtrack(constructed_sofar): - to_stop, reached_target = over(constructed_sofar) - if to_stop: - if reached_target: - print(constructed_sofar) - return - candidates = construct_candidates(constructed_sofar) - for candidate in candidates: - constructed_sofar.append(candidate) - backtrack(constructed_sofar[:]) - constructed_sofar.pop() - - -backtrack([]) - - -# Complexity: O(n(m+p)) - -# 1. Sort all the arrays - a,b,c. - This will improve average time complexity. -# 2. If c[i] < Sum, then look for Sum - c[i] in array a and b. When pair found, -# insert c[i], a[j] & b[k] into the result list. This can be done in O(n). -# 3. Keep on doing the above procedure while going through complete c array. - - -A = [1, 2, 3, 3] -B = [2, 3, 3, 4] -C = [1, 2, 2, 2] -S = 7 - - -def check_sum(n, *nums): - if sum(x for x in nums) == n: - return (True, nums) - else: - return (False, nums) - - -pro = itertools.product(A, B, C) -func = partial(check_sum, S) -sums = list(itertools.starmap(func, pro)) -res = set() -for s in sums: - if s[0] is True and s[1] not in res: - res.add(s[1]) -print(res) +def array_sum_combinations(A, B, C, target): + + def over(constructed_sofar): + sum = 0 + to_stop, reached_target = False, False + for elem in constructed_sofar: + sum += elem + if sum >= target or len(constructed_sofar) >= 3: + to_stop = True + if sum == target and 3 == len(constructed_sofar): + reached_target = True + return to_stop, reached_target + + def construct_candidates(constructed_sofar): + array = A + if 1 == len(constructed_sofar): + array = B + elif 2 == len(constructed_sofar): + array = C + return array + + def backtrack(constructed_sofar=[], res=[]): + to_stop, reached_target = over(constructed_sofar) + if to_stop: + if reached_target: + res.append(constructed_sofar) + return + candidates = construct_candidates(constructed_sofar) + + for candidate in candidates: + constructed_sofar.append(candidate) + backtrack(constructed_sofar[:], res) + constructed_sofar.pop() + + res = [] + backtrack([], res) + return res + + +def unique_array_sum_combinations(A, B, C, target): + """ + 1. Sort all the arrays - a,b,c. - This improves average time complexity. + 2. If c[i] < Sum, then look for Sum - c[i] in array a and b. + When pair found, insert c[i], a[j] & b[k] into the result list. + This can be done in O(n). + 3. Keep on doing the above procedure while going through complete c array. + + Complexity: O(n(m+p)) + """ + def check_sum(n, *nums): + if sum(x for x in nums) == n: + return (True, nums) + else: + return (False, nums) + + pro = itertools.product(A, B, C) + func = partial(check_sum, target) + sums = list(itertools.starmap(func, pro)) + + res = set() + for s in sums: + if s[0] is True and s[1] not in res: + res.add(s[1]) + + return list(res) diff --git a/algorithms/backtrack/combination_sum.py b/algorithms/backtrack/combination_sum.py index 8c6747681..4d4dfb176 100644 --- a/algorithms/backtrack/combination_sum.py +++ b/algorithms/backtrack/combination_sum.py @@ -16,18 +16,18 @@ """ -def combination_sum(self, candidates, target): +def combination_sum(candidates, target): + + def dfs(nums, target, index, path, res): + if target < 0: + return # backtracking + if target == 0: + res.append(path) + return + for i in range(index, len(nums)): + dfs(nums, target-nums[i], i, path+[nums[i]], res) + res = [] candidates.sort() - self.dfs(candidates, target, 0, [], res) + dfs(candidates, target, 0, [], res) return res - - -def dfs(self, nums, target, index, path, res): - if target < 0: - return # backtracking - if target == 0: - res.append(path) - return - for i in range(index, len(nums)): - self.dfs(nums, target-nums[i], i, path+[nums[i]], res) diff --git a/algorithms/backtrack/expression_add_operators.py b/algorithms/backtrack/expression_add_operators.py deleted file mode 100644 index f8f520f9c..000000000 --- a/algorithms/backtrack/expression_add_operators.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Given a string that contains only digits 0-9 and a target value, -return all possibilities to add binary operators (not unary) +, -, or * -between the digits so they prevuate to the target value. - -Examples: -"123", 6 -> ["1+2+3", "1*2*3"] -"232", 8 -> ["2*3+2", "2+3*2"] -"105", 5 -> ["1*0+5","10-5"] -"00", 0 -> ["0+0", "0-0", "0*0"] -"3456237490", 9191 -> [] -""" - -def add_operator(num, target): - """ - :type num: str - :type target: int - :rtype: List[str] - """ - res = [] - if not num: return res - helper(res, "", num, target, 0, 0, 0) - return res - - -def helper(res, path, num, target, pos, prev, multed): - if pos == len(num): - if target == prev: - res.append(path) - return - for i in range(pos, len(num)): - if i != pos and num[pos] == '0': # all digits have to be used - break - cur = int(num[pos:i+1]) - if pos == 0: - helper(res, path + str(cur), num, target, i+1, cur, cur) - else: - helper(res, path + "+" + str(cur), num, target, i+1, prev + cur, cur) - helper(res, path + "-" + str(cur), num, target, i+1, prev - cur, -cur) - helper(res, path + "*" + str(cur), num, target, i+1, prev - multed + multed * cur, multed * cur) - - -# "123", 6 -> ["1+2+3", "1*2*3"] -s = "123" -target = 6 -print(add_operator(s, target)) -# "232", 8 -> ["2*3+2", "2+3*2"] -s = "232" -target = 8 -print(add_operator(s, target)) - -s = "123045" -target = 3 -print(add_operator(s, target)) diff --git a/algorithms/backtrack/factor_combinations.py b/algorithms/backtrack/factor_combinations.py index d4de7288f..3240b05a8 100644 --- a/algorithms/backtrack/factor_combinations.py +++ b/algorithms/backtrack/factor_combinations.py @@ -3,7 +3,8 @@ 8 = 2 x 2 x 2; = 2 x 4. -Write a function that takes an integer n and return all possible combinations of its factors. +Write a function that takes an integer n +and return all possible combinations of its factors. Note: You may assume that n is always positive. @@ -49,7 +50,7 @@ def get_factors(n): # Recursive: -def get_factors_recur(n): +def recursive_get_factors(n): def factor(n, i, combi, combis): while i * i <= n: diff --git a/algorithms/backtrack/find_words.py b/algorithms/backtrack/find_words.py new file mode 100644 index 000000000..da6b6347a --- /dev/null +++ b/algorithms/backtrack/find_words.py @@ -0,0 +1,73 @@ +''' +Given a matrix of words and a list of words to search, +return a list of words that exists in the board +This is Word Search II on LeetCode + +board = [ + ['o','a','a','n'], + ['e','t','a','e'], + ['i','h','k','r'], + ['i','f','l','v'] + ] + +words = ["oath","pea","eat","rain"] +''' + + +def find_words(board, words): + + def backtrack(board, i, j, trie, pre, used, result): + ''' + backtrack tries to build each words from + the board and return all words found + + @param: board, the passed in board of characters + @param: i, the row index + @param: j, the column index + @param: trie, a trie of the passed in words + @param: pre, a buffer of currently build string that differs + by recursion stack + @param: used, a replica of the board except in booleans + to state whether a character has been used + @param: result, the resulting set that contains all words found + + @return: list of words found + ''' + + if '#' in trie: + result.add(pre) + + if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]): + return + + if not used[i][j] and board[i][j] in trie: + used[i][j] = True + backtrack(board, i+1, j, trie[board[i][j]], + pre+board[i][j], used, result) + backtrack(board, i, j+1, trie[board[i][j]], + pre+board[i][j], used, result) + backtrack(board, i-1, j, trie[board[i][j]], + pre+board[i][j], used, result) + backtrack(board, i, j-1, trie[board[i][j]], + pre+board[i][j], used, result) + used[i][j] = False + + # make a trie structure that is essentially dictionaries of dictionaries + # that map each character to a potential next character + trie = {} + for word in words: + curr_trie = trie + for char in word: + if char not in curr_trie: + curr_trie[char] = {} + curr_trie = curr_trie[char] + curr_trie['#'] = '#' + + # result is a set of found words since we do not want repeats + result = set() + used = [[False]*len(board[0]) for _ in range(len(board))] + + for i in range(len(board)): + for j in range(len(board[0])): + backtrack(board, i, j, trie, '', used, result) + return list(result) diff --git a/algorithms/backtrack/general_solution.md b/algorithms/backtrack/general_solution.md deleted file mode 100644 index 0c0ee0c6f..000000000 --- a/algorithms/backtrack/general_solution.md +++ /dev/null @@ -1,156 +0,0 @@ -This structure might apply to many other backtracking questions, but here I am just going to demonstrate Subsets, Permutations, and Combination Sum. - -# Subsets : https://leetcode.com/problems/subsets/ - -public List> subsets(int[] nums) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, 0); - return list; -} - -private void backtrack(List> list , List tempList, int [] nums, int start){ - list.add(new ArrayList<>(tempList)); - for(int i = start; i < nums.length; i++){ - tempList.add(nums[i]); - backtrack(list, tempList, nums, i + 1); - tempList.remove(tempList.size() - 1); - } -} - -# Subsets II (contains duplicates) : https://leetcode.com/problems/subsets-ii/ - -public List> subsetsWithDup(int[] nums) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, 0); - return list; -} - -private void backtrack(List> list, List tempList, int [] nums, int start){ - list.add(new ArrayList<>(tempList)); - for(int i = start; i < nums.length; i++){ - if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates - tempList.add(nums[i]); - backtrack(list, tempList, nums, i + 1); - tempList.remove(tempList.size() - 1); - } -} - -# Permutations : https://leetcode.com/problems/permutations/ - -public List> permute(int[] nums) { - List> list = new ArrayList<>(); - // Arrays.sort(nums); // not necessary - backtrack(list, new ArrayList<>(), nums); - return list; -} - -private void backtrack(List> list, List tempList, int [] nums){ - if(tempList.size() == nums.length){ - list.add(new ArrayList<>(tempList)); - } else{ - for(int i = 0; i < nums.length; i++){ - if(tempList.contains(nums[i])) continue; // element already exists, skip - tempList.add(nums[i]); - backtrack(list, tempList, nums); - tempList.remove(tempList.size() - 1); - } - } -} - -# Permutations II (contains duplicates) : https://leetcode.com/problems/permutations-ii/ - -public List> permuteUnique(int[] nums) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]); - return list; -} - -private void backtrack(List> list, List tempList, int [] nums, boolean [] used){ - if(tempList.size() == nums.length){ - list.add(new ArrayList<>(tempList)); - } else{ - for(int i = 0; i < nums.length; i++){ - if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue; - used[i] = true; - tempList.add(nums[i]); - backtrack(list, tempList, nums, used); - used[i] = false; - tempList.remove(tempList.size() - 1); - } - } -} - -# Combination Sum : https://leetcode.com/problems/combination-sum/ - -public List> combinationSum(int[] nums, int target) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, target, 0); - return list; -} - -private void backtrack(List> list, List tempList, int [] nums, int remain, int start){ - if(remain < 0) return; - else if(remain == 0) list.add(new ArrayList<>(tempList)); - else{ - for(int i = start; i < nums.length; i++){ - tempList.add(nums[i]); - backtrack(list, tempList, nums, remain - nums[i], i); // not i + 1 because we can reuse same elements - tempList.remove(tempList.size() - 1); - } - } -} -# Combination Sum II (can't reuse same element) : https://leetcode.com/problems/combination-sum-ii/ - -public List> combinationSum2(int[] nums, int target) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, target, 0); - return list; - -} - -private void backtrack(List> list, List tempList, int [] nums, int remain, int start){ - if(remain < 0) return; - else if(remain == 0) list.add(new ArrayList<>(tempList)); - else{ - for(int i = start; i < nums.length; i++){ - if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates - tempList.add(nums[i]); - backtrack(list, tempList, nums, remain - nums[i], i + 1); - tempList.remove(tempList.size() - 1); - } - } -} - - -# Palindrome Partitioning : https://leetcode.com/problems/palindrome-partitioning/ - -public List> partition(String s) { - List> list = new ArrayList<>(); - backtrack(list, new ArrayList<>(), s, 0); - return list; -} - -public void backtrack(List> list, List tempList, String s, int start){ - if(start == s.length()) - list.add(new ArrayList<>(tempList)); - else{ - for(int i = start; i < s.length(); i++){ - if(isPalindrome(s, start, i)){ - tempList.add(s.substring(start, i + 1)); - backtrack(list, tempList, s, i + 1); - tempList.remove(tempList.size() - 1); - } - } - } -} - -public boolean isPalindrome(String s, int low, int high){ - while(low < high) - if(s.charAt(low++) != s.charAt(high--)) return false; - return true; -} diff --git a/algorithms/backtrack/generate_abbreviations.py b/algorithms/backtrack/generate_abbreviations.py index 929c33994..132965687 100644 --- a/algorithms/backtrack/generate_abbreviations.py +++ b/algorithms/backtrack/generate_abbreviations.py @@ -6,21 +6,21 @@ def generate_abbreviations(word): - result = [] - backtrack(result, word, 0, 0, "") - return result + def backtrack(result, word, pos, count, cur): + if pos == len(word): + if count > 0: + cur += str(count) + result.append(cur) + return -def backtrack(result, word, pos, count, cur): - if pos == len(word): - if count > 0: - cur += str(count) - result.append(cur) - return + if count > 0: # add the current word + backtrack(result, word, pos+1, 0, cur+str(count)+word[pos]) + else: + backtrack(result, word, pos+1, 0, cur+word[pos]) + # skip the current word + backtrack(result, word, pos+1, count+1, cur) - if count > 0: # add the current word - backtrack(result, word, pos+1, 0, cur+str(count)+word[pos]) - else: - backtrack(result, word, pos+1, 0, cur+word[pos]) - # skip the current word - backtrack(result, word, pos+1, count+1, cur) + result = [] + backtrack(result, word, 0, 0, "") + return result diff --git a/algorithms/backtrack/generate_parenthesis.py b/algorithms/backtrack/generate_parenthesis.py index 6dac22c94..9b9eb8cf1 100644 --- a/algorithms/backtrack/generate_parenthesis.py +++ b/algorithms/backtrack/generate_parenthesis.py @@ -13,20 +13,17 @@ ] """ -def gen_parenthesis(n:"int")->"List[str]": + +def generate_parenthesis(n): + def add_pair(res, s, left, right): + if left == 0 and right == 0: + res.append(s) + return + if right > 0: + add_pair(res, s+")", left, right-1) + if left > 0: + add_pair(res, s+"(", left-1, right+1) + res = [] add_pair(res, "", n, 0) return res - -def add_pair(res, s, left, right): - if left == 0 and right == 0: - res.append(s) - return - if right > 0: - add_pair(res, s+")", left, right-1) - if left > 0: - add_pair(res, s+"(", left-1, right+1) - - -if __name__=="__main__": - print(gen_parenthesis(3)) diff --git a/algorithms/backtrack/letter_combination.py b/algorithms/backtrack/letter_combination.py index f4a4c4e0b..8a2f8d151 100644 --- a/algorithms/backtrack/letter_combination.py +++ b/algorithms/backtrack/letter_combination.py @@ -7,7 +7,7 @@ """ -def letter_combinations(digits:"str")->"List[str]": +def letter_combinations(digits): if digits == "": return [] kmaps = { @@ -28,8 +28,3 @@ def letter_combinations(digits:"str")->"List[str]": tmp.append(an + char) ans = tmp return ans - - -if __name__ == "__main__": - digit_string = "23" - print(letter_combinations(digit_string)) diff --git a/algorithms/backtrack/palindrome_partitioning.py b/algorithms/backtrack/palindrome_partitioning.py index 21500c180..052339dcc 100644 --- a/algorithms/backtrack/palindrome_partitioning.py +++ b/algorithms/backtrack/palindrome_partitioning.py @@ -1,8 +1,11 @@ """ It looks like you need to be looking not for all palindromic substrings, -but rather for all the ways you can divide the input string up into palindromic substrings. -(There's always at least one way, since one-character substrings are always palindromes.) +but rather for all the ways you can divide the input string +up into palindromic substrings. +(There's always at least one way, +since one-character substrings are always palindromes.) """ + def palindromic_substrings(s): if not s: return [[]] @@ -14,19 +17,26 @@ def palindromic_substrings(s): results.append([sub] + rest) return results -""" There's two loops. -The outer loop checks each length of initial substring (in descending length order) to see -if it is a palindrome. If so, it recurses on the rest of the string and loops over the returned -values, adding the initial substring to each item before adding it to the results. + +""" +There's two loops. +The outer loop checks each length of initial substring +(in descending length order) to see if it is a palindrome. +If so, it recurses on the rest of the string and loops over the returned +values, adding the initial substring to +each item before adding it to the results. """ -# A slightly more Pythonic approach would be to make a recursive generator: -def palindromic_substrings(s): + +def palindromic_substrings_iter(s): + """ + A slightly more Pythonic approach with a recursive generator + """ if not s: yield [] return for i in range(len(s), 0, -1): sub = s[:i] if sub == sub[::-1]: - for rest in palindromic_substrings(s[i:]): + for rest in palindromic_substrings_iter(s[i:]): yield [sub] + rest diff --git a/algorithms/backtrack/pattern_match.py b/algorithms/backtrack/pattern_match.py index 532dfb9c2..03a23a4e9 100644 --- a/algorithms/backtrack/pattern_match.py +++ b/algorithms/backtrack/pattern_match.py @@ -20,33 +20,23 @@ def pattern_match(pattern, string): :type string: str :rtype: bool """ - return backtrack(pattern, string, {}) + def backtrack(pattern, string, dic): + + if len(pattern) == 0 and len(string) > 0: + return False + if len(pattern) == len(string) == 0: + return True -def backtrack(pattern, string, dic): - print(dic) - if len(pattern) == 0 and len(string) > 0: + for end in range(1, len(string)-len(pattern)+2): + if pattern[0] not in dic and string[:end] not in dic.values(): + dic[pattern[0]] = string[:end] + if backtrack(pattern[1:], string[end:], dic): + return True + del dic[pattern[0]] + elif pattern[0] in dic and dic[pattern[0]] == string[:end]: + if backtrack(pattern[1:], string[end:], dic): + return True return False - if len(pattern) == len(string) == 0: - return True - for end in range(1, len(string)-len(pattern)+2): - if pattern[0] not in dic and string[:end] not in dic.values(): - dic[pattern[0]] = string[:end] - if backtrack(pattern[1:], string[end:], dic): - return True - del dic[pattern[0]] - elif pattern[0] in dic and dic[pattern[0]] == string[:end]: - if backtrack(pattern[1:], string[end:], dic): - return True - return False - -if __name__ == "__main__": - pattern1 = "abab" - string1 = "redblueredblue" - pattern2 = "aaaa" - string2 = "asdasdasdasd" - pattern3 = "aabb" - string3 = "xyzabcxzyabc" - print(pattern_match(pattern1, string1)) - print(pattern_match(pattern2, string2)) - print(pattern_match(pattern3, string3)) + + return backtrack(pattern, string, {}) diff --git a/algorithms/backtrack/permute.py b/algorithms/backtrack/permute.py index 397597230..4ce484369 100644 --- a/algorithms/backtrack/permute.py +++ b/algorithms/backtrack/permute.py @@ -1,40 +1,54 @@ -# Given a collection of distinct numbers, return all possible permutations. - -# For example, -# [1,2,3] have the following permutations: -# [ - # [1,2,3], - # [1,3,2], - # [2,1,3], - # [2,3,1], - # [3,1,2], - # [3,2,1] -# ] - -def permute(nums): - perms = [[]] - for n in nums: - new_perms = [] - for perm in perms: - for i in range(len(perm)+1): - new_perms.append(perm[:i] + [n] + perm[i:]) ###insert n - print(i, perm[:i], [n], perm[i:], ">>>>", new_perms) - perms = new_perms - return perms +""" +Given a collection of distinct numbers, return all possible permutations. + +For example, +[1,2,3] have the following permutations: +[ + [1,2,3], + [1,3,2], + [2,1,3], + [2,3,1], + [3,1,2], + [3,2,1] +] +""" + + +def permute(elements): + """ + returns a list with the permuations. + """ + if len(elements) <= 1: + return elements + else: + tmp = [] + for perm in permute(elements[1:]): + for i in range(len(elements)): + tmp.append(perm[:i] + elements[0:1] + perm[i:]) + return tmp + + +def permute_iter(elements): + """ + iterator: returns a perumation by each call. + """ + if len(elements) <= 1: + yield elements + else: + for perm in permute_iter(elements[1:]): + for i in range(len(elements)): + yield perm[:i] + elements[0:1] + perm[i:] + # DFS Version -# def permute(nums): - # res = [] - # dfs(res, nums, []) - # return res - -# def dfs(res, nums, path): - # if not nums: - # res.append(path) - # for i in range(len(nums)): - # print(nums[:i]+nums[i+1:]) - # dfs(res, nums[:i]+nums[i+1:], path+[nums[i]]) - -test = [1,2,3] -print(test) -print(permute(test)) +def permute_recursive(nums): + def dfs(res, nums, path): + if not nums: + res.append(path) + for i in range(len(nums)): + print(nums[:i]+nums[i+1:]) + dfs(res, nums[:i]+nums[i+1:], path+[nums[i]]) + + res = [] + dfs(res, nums, []) + return res diff --git a/algorithms/backtrack/permute_unique.py b/algorithms/backtrack/permute_unique.py index 911d40c76..3b82e2c46 100644 --- a/algorithms/backtrack/permute_unique.py +++ b/algorithms/backtrack/permute_unique.py @@ -1,13 +1,16 @@ -# Given a collection of numbers that might contain duplicates, -# return all possible unique permutations. +""" +Given a collection of numbers that might contain duplicates, +return all possible unique permutations. + +For example, +[1,1,2] have the following unique permutations: +[ + [1,1,2], + [1,2,1], + [2,1,1] +] +""" -# For example, -# [1,1,2] have the following unique permutations: -# [ - # [1,1,2], - # [1,2,1], - # [2,1,1] -# ] def permute_unique(nums): perms = [[]] @@ -16,9 +19,7 @@ def permute_unique(nums): for l in perms: for i in range(len(l)+1): new_perms.append(l[:i]+[n]+l[i:]) - if i= len(nums): - # res.append(cur) - # else: - # backtrack(res, nums, cur+[nums[pos]], pos+1) - # backtrack(res, nums, cur, pos+1) +def backtrack(res, nums, cur, pos): + if pos >= len(nums): + res.append(cur) + else: + backtrack(res, nums, cur+[nums[pos]], pos+1) + backtrack(res, nums, cur, pos+1) +""" # Iteratively -def subsets2(self, nums): +def subsets_v2(self, nums): res = [[]] for num in sorted(nums): res += [item+[num] for item in res] return res -test = [1,2,3] + +test = [1, 2, 3] print(test) print(subsets(test)) diff --git a/algorithms/backtrack/subsets_unique.py b/algorithms/backtrack/subsets_unique.py index fac0cb0c2..a99f25c35 100644 --- a/algorithms/backtrack/subsets_unique.py +++ b/algorithms/backtrack/subsets_unique.py @@ -1,38 +1,42 @@ -# Given a collection of integers that might contain duplicates, nums, -# return all possible subsets. +""" +Given a collection of integers that might contain duplicates, nums, +return all possible subsets. -# Note: The solution set must not contain duplicate subsets. +Note: The solution set must not contain duplicate subsets. -# For example, -# If nums = [1,2,2], a solution is: +For example, +If nums = [1,2,2], a solution is: + +[ + [2], + [1], + [1,2,2], + [2,2], + [1,2], + [] +] +""" -# [ - # [2], - # [1], - # [1,2,2], - # [2,2], - # [1,2], - # [] -# ] def subsets_unique(nums): + + def backtrack(res, nums, stack, pos): + if pos == len(nums): + res.add(tuple(stack)) + else: + # take + stack.append(nums[pos]) + backtrack(res, nums, stack, pos+1) + stack.pop() + + # don't take + backtrack(res, nums, stack, pos+1) + res = set() backtrack(res, nums, [], 0) return list(res) -def backtrack(res, nums, stack, pos): - if pos == len(nums): - res.add(tuple(stack)) - else: - # take - stack.append(nums[pos]) - backtrack(res, nums, stack, pos+1) - stack.pop() - - # don't take - backtrack(res, nums, stack, pos+1) - -test = [1,2,2] +test = [1, 2, 2] print(test) print(subsets_unique(test)) diff --git a/algorithms/backtrack/word_search.py b/algorithms/backtrack/word_search.py deleted file mode 100644 index 989e5b29c..000000000 --- a/algorithms/backtrack/word_search.py +++ /dev/null @@ -1,111 +0,0 @@ -import unittest -''' -Given a matrix of words and a list of words to search, return a list of words that exists in the board -This is Word Search II on LeetCode - -board = [ - ['o','a','a','n'], - ['e','t','a','e'], - ['i','h','k','r'], - ['i','f','l','v'] - ] - -words = ["oath","pea","eat","rain"] - -''' - -def find_words(board, words): - # make a trie structure that is essentially dictionaries of dictionaries that map each character to a potential next character - trie = {} - for word in words: - curr_trie = trie - for char in word: - if char not in curr_trie: - curr_trie[char] = {} - curr_trie = curr_trie[char] - curr_trie['#'] = '#' - - # result is a set of found words since we do not want repeats - result = set() - used = [[False]*len(board[0]) for _ in range(len(board))] - - for i in range(len(board)): - for j in range(len(board[0])): - backtrack(board, i, j, trie, '', used, result) - return list(result) - -''' -backtrack tries to build each words from the board and return all words found -@param: board, the passed in board of characters -@param: i, the row index -@param: j, the column index -@param: trie, a trie of the passed in words -@param: pre, a buffer of currently build string that differs by recursion stack -@param: used, a replica of the board except in booleans to state whether a character has been used -@param: result, the resulting set that contains all words found - -@return: list of words found -''' - -def backtrack(board, i, j, trie, pre, used, result): - if '#' in trie: - result.add(pre) - - if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]): - return - - if not used[i][j] and board[i][j] in trie: - used[i][j]=True - backtrack(board,i+1,j,trie[board[i][j]],pre+board[i][j], used, result) - backtrack(board,i,j+1,trie[board[i][j]],pre+board[i][j], used, result) - backtrack(board,i-1,j,trie[board[i][j]],pre+board[i][j], used, result) - backtrack(board,i,j-1,trie[board[i][j]],pre+board[i][j], used, result) - used[i][j]=False - -class MyTests(unittest.TestCase): - def test_normal(self): - board = [ - ['o','a','a','n'], - ['e','t','a','e'], - ['i','h','k','r'], - ['i','f','l','v'] - ] - - words = ["oath","pea","eat","rain"] - self.assertEqual(find_words(board, words), ['oath', 'eat']) - - def test_none(self): - board = [ - ['o','a','a','n'], - ['e','t','a','e'], - ['i','h','k','r'], - ['i','f','l','v'] - ] - - words = ["chicken", "nugget", "hello", "world"] - self.assertEqual(find_words(board, words), []) - - def test_empty(self): - board = [] - words = [] - self.assertEqual(find_words(board, words), []) - - def test_uneven(self): - board = [ - ['o','a','a','n'], - ['e','t','a','e'] - ] - words = ["oath","pea","eat","rain"] - self.assertEqual(find_words(board, words), ['eat']) - - def test_repeat(self): - board = [ - ['a','a','a'], - ['a','a','a'], - ['a','a','a'] - ] - words = ["a", "aa", "aaa", "aaaa", "aaaaa"] - self.assertTrue(len(find_words(board, words))==5) - -if __name__=="__main__": - unittest.main() diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py new file mode 100644 index 000000000..2e01d596c --- /dev/null +++ b/tests/test_backtrack.py @@ -0,0 +1,170 @@ +from algorithms.backtrack import ( + add_operators, + permute, + permute_iter, + anagram, + array_sum_combinations, + unique_array_sum_combinations, + combination_sum, + find_words, + pattern_match, +) + +import unittest + + +class TestAddOperator(unittest.TestCase): + def test_add_operators(self): + # "123", 6 -> ["1+2+3", "1*2*3"] + s = "123" + target = 6 + self.assertEqual(add_operators(s, target), ["1+2+3", "1*2*3"]) + # "232", 8 -> ["2*3+2", "2+3*2"] + s = "232" + target = 8 + self.assertEqual(add_operators(s, target), ["2+3*2", "2*3+2"]) + + s = "123045" + target = 3 + answer = ['1+2+3*0*4*5', + '1+2+3*0*45', + '1+2-3*0*4*5', + '1+2-3*0*45', + '1-2+3+0-4+5', + '1-2+3-0-4+5', + '1*2+3*0-4+5', + '1*2-3*0-4+5', + '1*23+0-4*5', + '1*23-0-4*5', + '12+3*0-4-5', + '12-3*0-4-5'] + self.assertEqual(add_operators(s, target), answer) + + +class TestPermuteAndAnagram(unittest.TestCase): + + def test_permute(self): + perms = ['abc', 'bac', 'bca', 'acb', 'cab', 'cba'] + self.assertEqual(perms, permute("abc")) + + def test_permute_iter(self): + it = permute_iter("abc") + perms = ['abc', 'bac', 'bca', 'acb', 'cab', 'cba'] + for i in range(len(perms)): + self.assertEqual(perms[i], next(it)) + + def test_angram(self): + self.assertTrue(anagram('apple', 'pleap')) + self.assertFalse(anagram("apple", "cherry")) + + +class TestArrayCombinationSum(unittest.TestCase): + + def test_array_sum_combinations(self): + A = [1, 2, 3, 3] + B = [2, 3, 3, 4] + C = [2, 3, 3, 4] + target = 7 + answer = [[1, 2, 4], [1, 3, 3], [1, 3, 3], [1, 3, 3], + [1, 3, 3], [1, 4, 2], [2, 2, 3], [2, 2, 3], + [2, 3, 2], [2, 3, 2], [3, 2, 2], [3, 2, 2]] + self.assertEqual(array_sum_combinations(A, B, C, target), answer) + + def test_unique_array_sum_combinations(self): + A = [1, 2, 3, 3] + B = [2, 3, 3, 4] + C = [2, 3, 3, 4] + target = 7 + answer = [(2, 3, 2), (3, 2, 2), (1, 2, 4), + (1, 4, 2), (2, 2, 3), (1, 3, 3)] + self.assertEqual(unique_array_sum_combinations(A, B, C, target), answer) + + +class TestCombinationSum(unittest.TestCase): + + def check_sum(self, nums, target): + if sum(nums) == target: + return (True, nums) + else: + return (False, nums) + + def test_combination_sum(self): + candidates1 = [2, 3, 6, 7] + target1 = 7 + answer1 = [ + [2, 2, 3], + [7] + ] + self.assertEqual(combination_sum(candidates1, target1), answer1) + + candidates2 = [2, 3, 5] + target2 = 8 + answer2 = [ + [2, 2, 2, 2], + [2, 3, 3], + [3, 5] + ] + self.assertEqual(combination_sum(candidates2, target2), answer2) + + +class TestFindWords(unittest.TestCase): + + def test_normal(self): + board = [ + ['o', 'a', 'a', 'n'], + ['e', 't', 'a', 'e'], + ['i', 'h', 'k', 'r'], + ['i', 'f', 'l', 'v'] + ] + + words = ["oath", "pea", "eat", "rain"] + self.assertEqual(find_words(board, words).sort(), + ['oath', 'eat'].sort()) + + def test_none(self): + board = [ + ['o', 'a', 'a', 'n'], + ['e', 't', 'a', 'e'], + ['i', 'h', 'k', 'r'], + ['i', 'f', 'l', 'v'] + ] + + words = ["chicken", "nugget", "hello", "world"] + self.assertEqual(find_words(board, words), []) + + def test_empty(self): + board = [] + words = [] + self.assertEqual(find_words(board, words), []) + + def test_uneven(self): + board = [ + ['o', 'a', 'a', 'n'], + ['e', 't', 'a', 'e'] + ] + words = ["oath", "pea", "eat", "rain"] + self.assertEqual(find_words(board, words), ['eat']) + + def test_repeat(self): + board = [ + ['a', 'a', 'a'], + ['a', 'a', 'a'], + ['a', 'a', 'a'] + ] + words = ["a", "aa", "aaa", "aaaa", "aaaaa"] + self.assertTrue(len(find_words(board, words)) == 5) + + +class TestPatternMatch(unittest.TestCase): + + def test_pattern_match(self): + pattern1 = "abab" + string1 = "redblueredblue" + pattern2 = "aaaa" + string2 = "asdasdasdasd" + pattern3 = "aabb" + string3 = "xyzabcxzyabc" + + self.assertTrue(pattern_match(pattern1, string1)) + self.assertTrue(pattern_match(pattern2, string2)) + self.assertFalse(pattern_match(pattern3, string3)) From de286fda83051b981d2c8745086579b43d138887 Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Wed, 6 Jun 2018 16:51:42 +0530 Subject: [PATCH 054/302] add type of desc. as markdown (#324) fixes #322 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 65a80c638..f08f24f14 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ def long_description(): version='0.1.0', description='Pythonic Data Structures and Algorithms', long_description=long_description(), + long_description_content_type="text/markdown", url='https://github.com/keon/algorithms', author='Algorithms Team & Contributors', author_email="kwk236@gmail.com", From 69d4b7dc2988ce34b92772a04558aeaeefd63019 Mon Sep 17 00:00:00 2001 From: hsi1032 Date: Thu, 7 Jun 2018 15:31:01 +0900 Subject: [PATCH 055/302] Create bitonic_sort.py in /algorithms/sort/ and update test_sort, __init__ and all README files (#317) * Create bitonic_sort.py * Update __init__.py * Update test_sort.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update bitonic_sort.py * Update bitonic_sort.py * Update bitonic_sort.py * Update test_sort.py * Update test_sort.py * Update bitonic_sort.py * Update bitonic_sort.py * Update bitonic_sort.py * Update bitonic_sort.py * Update bitonic_sort.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/bitonic_sort.py | 43 +++++++++++++++++++++++++++++++++ tests/test_sort.py | 9 +++++++ 8 files changed, 58 insertions(+) create mode 100644 algorithms/sort/bitonic_sort.py diff --git a/README.md b/README.md index f31075f57..69b550d4d 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,7 @@ If you want to uninstall algorithms, it is as simple as: - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) diff --git a/README_CN.md b/README_CN.md index 4e938223e..260bed27b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -206,6 +206,7 @@ pip3 uninstall -y algorithms - [randomized_set:随机集合](algorithms/set/randomized_set.py) - [set_covering:集合覆盖](algorithms/set/set_covering.py) - [sort:排序](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) diff --git a/README_GE.md b/README_GE.md index 8bc1fd2a5..2ec4b7aa5 100644 --- a/README_GE.md +++ b/README_GE.md @@ -227,6 +227,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) diff --git a/README_JP.md b/README_JP.md index 0e63b9c09..627955749 100644 --- a/README_JP.md +++ b/README_JP.md @@ -221,6 +221,7 @@ if __name__ == "__main__": - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort : ソート](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [bucket_sort](algorithms/sort/bucket_sort.py) diff --git a/README_KR.md b/README_KR.md index fde2147b7..d46fa4774 100644 --- a/README_KR.md +++ b/README_KR.md @@ -218,6 +218,7 @@ if __name__ == "__main__": - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) - [sort : 정렬 알고리즘](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) - [bogo_sort](algorithms/sort/bogo_sort.py) - [bubble_sort](algorithms/sort/bubble_sort.py) - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index a2c6d3c6f..a7dba9a16 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -1,3 +1,4 @@ +from .bitonic_sort import * from .bogo_sort import * from .bubble_sort import * from .comb_sort import * diff --git a/algorithms/sort/bitonic_sort.py b/algorithms/sort/bitonic_sort.py new file mode 100644 index 000000000..f8cad90e1 --- /dev/null +++ b/algorithms/sort/bitonic_sort.py @@ -0,0 +1,43 @@ +def bitonic_sort(arr, reverse=False): + """ + bitonic sort is sorting algorithm to use multiple process, but this code not containing parallel process + It can sort only array that sizes power of 2 + It can sort array in both increasing order and decreasing order by giving argument true(increasing) and false(decreasing) + + Worst-case in parallel: O(log(n)^2) + Worst-case in non-parallel: O(nlog(n)^2) + + reference: https://en.wikipedia.org/wiki/Bitonic_sorter + """ + def compare(arr, reverse): + n = len(arr)//2 + for i in range(n): + if reverse != (arr[i] > arr[i+n]): + arr[i], arr[i+n] = arr[i+n], arr[i] + return arr + + def bitonic_merge(arr, reverse): + n = len(arr) + + if n <= 1: + return arr + + arr = compare(arr, reverse) + left = bitonic_merge(arr[:n // 2], reverse) + right = bitonic_merge(arr[n // 2:], reverse) + return left + right + + #end of function(compare and bitionic_merge) definition + n = len(arr) + if n <= 1: + return arr + # checks if n is power of two + if not (n and (not(n & (n - 1))) ): + raise ValueError("the size of input should be power of two") + + left = bitonic_sort(arr[:n // 2], True) + right = bitonic_sort(arr[n // 2:], False) + + arr = bitonic_merge(left + right, reverse) + + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index 020b9a343..7d8ea8a9b 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -1,4 +1,5 @@ from algorithms.sort import ( + bitonic_sort, bogo_sort, bubble_sort, comb_sort, @@ -22,6 +23,14 @@ class TestSuite(unittest.TestCase): def test_bogo_sort(self): self.assertEqual([1, 5, 23], bogo_sort([1, 23, 5])) + + def test_bitonic_sort(self): + self.assertEqual([1, 2, 3, 5, 23, 57, 65, 1232], + bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232])) + self.assertEqual([1, 2, 3, 5, 23, 57, 65, 1232], + bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232],False)) + self.assertEqual([1232, 65, 57, 23, 5, 3, 2, 1], + bitonic_sort([1, 2, 3, 5, 65, 23, 57, 1232],True)) def test_bubble_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], From 41dbd32d78b8eca5063e0728354d8a605821ef1a Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Thu, 7 Jun 2018 19:14:07 +0900 Subject: [PATCH 056/302] Added simulation in bubble sort (#327) * Update bubble_sort.py * Update bubble_sort.py * Update bubble_sort.py * Update bubble_sort.py --- algorithms/sort/bubble_sort.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/algorithms/sort/bubble_sort.py b/algorithms/sort/bubble_sort.py index 0a8a47063..63c6c4f14 100644 --- a/algorithms/sort/bubble_sort.py +++ b/algorithms/sort/bubble_sort.py @@ -4,19 +4,29 @@ Worst-case performance: O(N^2) +If you call bubble_sort(arr,True), you can see the process of the sort +Default is simulation = False + """ -def bubble_sort(arr): +def bubble_sort(arr, simulation=False): def swap(i, j): arr[i], arr[j] = arr[j], arr[i] n = len(arr) swapped = True + + if simulation: + print(arr) + while swapped: swapped = False for i in range(1, n): if arr[i - 1] > arr[i]: swap(i - 1, i) swapped = True + if simulation: + print(arr) + return arr From a93acad6f1a5c66f3f0938d9b6d0279cc1db1c72 Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Thu, 7 Jun 2018 16:26:12 +0530 Subject: [PATCH 057/302] logo update in all READMEs (#329) * add logo in README_CN * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README_CN.md | 2 ++ README_GE.md | 2 ++ README_JP.md | 2 ++ README_KR.md | 2 ++ 4 files changed, 8 insertions(+) diff --git a/README_CN.md b/README_CN.md index 260bed27b..0f5793e27 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,3 +1,5 @@ +

+ [English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_GE.md b/README_GE.md index 2ec4b7aa5..dc493bc3a 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,3 +1,5 @@ +

+ [English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_JP.md b/README_JP.md index 627955749..15d244c2f 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,3 +1,5 @@ +

+ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_KR.md b/README_KR.md index d46fa4774..678798851 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,3 +1,5 @@ +

+ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) From e5b9faca86889455b03b573b17802c648b75a5f7 Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Thu, 7 Jun 2018 04:48:33 -0700 Subject: [PATCH 058/302] WIP: Fix some issues in Travis and add more python env (#323) * Requirements.txt: Add requirements dependency for algorithms * Update cache in travis * Switch to use tox and add more env in python for testing * Add MANIFEST.in file * fix travis issue (#1) * Add TODO to PriorityQueue --- .travis.yml | 32 +++++++-------------- MANIFEST.in | 4 +++ requirements.txt | 6 ++++ tests/test_backtrack.py | 6 ++-- tests/test_queues.py | 8 ++++-- tox.ini | 64 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 MANIFEST.in create mode 100644 tox.ini diff --git a/.travis.yml b/.travis.yml index b3be12855..11468847b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,18 @@ group: travis_latest language: python -cache: pip -python: - - 3.6 - #- nightly - #- pypy3 +cache: + directories: + - $HOME/.cache/pip matrix: - allow_failures: - - python: nightly - - python: pypy3 + include: + - python: 3.4 + env: TOX_ENV=py34 + - python: 3.5 + env: TOX_ENV=py35,coverage + - python: 3.6 + env: TOX_ENV=py36 install: - pip install -r requirements.txt - - pip install flake8 # pytest # add another testing frameworks later - - pip install python-coveralls - - pip install coverage - - pip install nose before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics @@ -23,17 +21,9 @@ before_script: script: # Check python install package - pip3 install -e . - # Check unittest running - - python3 -m unittest discover tests - # Check pytest running - - python3 -m pytest tests - # Run nose with coverage support - - nosetests --with-coverage + - tox -e $TOX_ENV # Check python uninstall package - pip3 uninstall -y algorithms notifications: on_success: change on_failure: change # `always` will be the setting once code changes slow down - -after_success: - - coveralls diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..daf8a5200 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include README.md +include LICENSE +include algorithms/* +include tests/* diff --git a/requirements.txt b/requirements.txt index e69de29bb..7a3e47c8a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,6 @@ +flake8 +python-coveralls +coverage +nose +pytest +tox diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py index 2e01d596c..dd290f759 100644 --- a/tests/test_backtrack.py +++ b/tests/test_backtrack.py @@ -68,7 +68,8 @@ def test_array_sum_combinations(self): answer = [[1, 2, 4], [1, 3, 3], [1, 3, 3], [1, 3, 3], [1, 3, 3], [1, 4, 2], [2, 2, 3], [2, 2, 3], [2, 3, 2], [2, 3, 2], [3, 2, 2], [3, 2, 2]] - self.assertEqual(array_sum_combinations(A, B, C, target), answer) + answer.sort() + self.assertListEqual(sorted(array_sum_combinations(A, B, C, target)), answer) def test_unique_array_sum_combinations(self): A = [1, 2, 3, 3] @@ -77,7 +78,8 @@ def test_unique_array_sum_combinations(self): target = 7 answer = [(2, 3, 2), (3, 2, 2), (1, 2, 4), (1, 4, 2), (2, 2, 3), (1, 3, 3)] - self.assertEqual(unique_array_sum_combinations(A, B, C, target), answer) + answer.sort() + self.assertListEqual(sorted(unique_array_sum_combinations(A, B, C, target)), answer) class TestCombinationSum(unittest.TestCase): diff --git a/tests/test_queues.py b/tests/test_queues.py index e5a882abd..2c85c4508 100644 --- a/tests/test_queues.py +++ b/tests/test_queues.py @@ -88,10 +88,12 @@ def test_reconstruct_queue(self): self.assertEqual([[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]], reconstruct_queue([[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]])) +""" + TODO: Refactor PriorityQueue because insert method does not work for python3.4 class TestPriorityQueue(unittest.TestCase): - """ + Test suite for the PriorityQueue data structures. - """ + def test_PriorityQueue(self): queue = PriorityQueue() queue.push(3) @@ -100,7 +102,7 @@ def test_PriorityQueue(self): queue.push(6) self.assertEqual(4,queue.size()) self.assertEqual(str(1) + ": " + str(1),str(queue.pop())) - +""" if __name__ == "__main__": unittest.main() diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..b6f350603 --- /dev/null +++ b/tox.ini @@ -0,0 +1,64 @@ +[tox] +envlist = + py34 + py35 + py36 + coverage + +[testenv] +passenv = TRAVIS TRAVIS_* +basepython = + py34: python3.4 + py35: python3.5 + py36: python3.6 + py37: python3.7 +deps = + coverage + coveralls +commands = + coverage run --source=tests,algorithms -m unittest discover tests + coverage report -m + coveralls + +[testenv:py34] +passenv = CI TRAVIS TRAVIS_* +basepython = + python3.4 +deps = + pytest +commands = + python3 -m unittest discover tests + python3 -m pytest tests + +[testenv:py35] +passenv = CI TRAVIS TRAVIS_* +basepython = + python3.5 +deps = + pytest +commands = + python3 -m unittest discover tests + python3 -m pytest tests + +[testenv:py36] +passenv = CI TRAVIS TRAVIS_* +basepython = + python3.4 +deps = + pytest +commands = + python3 -m unittest discover tests + python3 -m pytest tests + +[testenv:coverage] +passenv = CI TRAVIS TRAVIS_* +skip_install = True +basepython = + python3.5 +commands = + coverage run --source=tests,algorithms -m unittest discover tests + coverage report -m + coveralls +deps = + coverage + coveralls From 6636026bde2ea0915c28201d802070848d362bb3 Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Thu, 7 Jun 2018 17:32:43 +0530 Subject: [PATCH 059/302] Update tree.md (#332) --- tree.md | 117 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/tree.md b/tree.md index 069df396d..adaa28165 100644 --- a/tree.md +++ b/tree.md @@ -1,52 +1,64 @@ ``` -. -├── array -│   ├── circular_counter.py +algorithms +├── arrays +│   ├── delete_nth.py │   ├── flatten.py │   ├── garage.py +│   ├── __init__.py +│   ├── josephus.py │   ├── longest_non_repeat.py +│   ├── max_ones_index.py │   ├── merge_intervals.py │   ├── missing_ranges.py +│   ├── move_zeros.py │   ├── plus_one.py -│   ├── rotate_array.py -│   ├── summary_ranges.py +│   ├── rotate.py +│   ├── summarize_ranges.py │   ├── three_sum.py │   └── two_sum.py ├── backtrack +│   ├── add_operators.py │   ├── anagram.py │   ├── array_sum_combinations.py │   ├── combination_sum.py -│   ├── expression_add_operators.py │   ├── factor_combinations.py -│   ├── general_solution.md +│   ├── find_words.py │   ├── generate_abbreviations.py │   ├── generate_parenthesis.py +│   ├── __init__.py │   ├── letter_combination.py │   ├── palindrome_partitioning.py │   ├── pattern_match.py │   ├── permute.py │   ├── permute_unique.py │   ├── subsets.py -│   ├── subsets_unique.py -│   └── word_search.py +│   └── subsets_unique.py ├── bfs │   ├── shortest_distance_from_all_buildings.py │   └── word_ladder.py ├── bit │   ├── add_bitwise_operator.py +│   ├── bit_operation.py │   ├── bytes_int_conversion.py +│   ├── count_flips_to_convert.py │   ├── count_ones.py +│   ├── find_difference.py │   ├── find_missing_number.py +│   ├── flip_bit_longest_sequence.py +│   ├── has_alternative_bit.py +│   ├── __init__.py +│   ├── insert_bit.py │   ├── power_of_two.py +│   ├── remove_bit.py │   ├── reverse_bits.py │   ├── single_number2.py +│   ├── single_number3.py │   ├── single_number.py -│   └── subsets.py +│   ├── subsets.py +│   └── swap_pair.py ├── calculator │   └── math_parser.py -├── CODE_OF_CONDUCT.md -├── CONTRIBUTING.md ├── dfs │   ├── all_factors.py │   ├── count_islands.py @@ -59,6 +71,7 @@ │   ├── coin_change.py │   ├── combination_sum.py │   ├── egg_drop.py +│   ├── fib.py │   ├── house_robber.py │   ├── job_scheduling.py │   ├── knapsack.py @@ -75,9 +88,11 @@ │   ├── checkDiGraphStronglyConnected.py │   ├── clone_graph.py │   ├── cycle_detection.py +│   ├── dijkstra.py │   ├── find_all_cliques.py │   ├── find_path.py │   ├── graph.py +│   ├── __init__.py │   ├── markov_chain.py │   ├── minimum_spanning_tree.py │   ├── pathBetweenTwoVerticesInDiGraph.py @@ -86,22 +101,28 @@ │   ├── Transitive_Closure_DFS.py │   └── traversal.py ├── heap +│   ├── binary_heap.py +│   ├── __init__.py │   ├── merge_sorted_k_lists.py │   ├── skyline.py │   └── sliding_window_max.py -├── LICENSE +├── __init__.py ├── linkedlist │   ├── add_two_numbers.py │   ├── copy_random_pointer.py │   ├── delete_node.py │   ├── first_cyclic_node.py +│   ├── __init__.py │   ├── intersection.py │   ├── is_cyclic.py │   ├── is_palindrome.py +│   ├── is_sorted.py │   ├── kth_to_last.py │   ├── linkedlist.py +│   ├── merge_two_list.py │   ├── partition.py │   ├── remove_duplicates.py +│   ├── remove_range.py │   ├── reverse.py │   ├── rotate_list.py │   └── swap_in_pairs.py @@ -109,21 +130,27 @@ │   ├── hashtable.py │   ├── longest_common_subsequence.py │   ├── randomized_set.py +│   ├── separate_chaining_hashtable.py │   └── valid_sudoku.py ├── maths │   ├── base_conversion.py +│   ├── combination.py │   ├── extended_gcd.py +│   ├── factorial.py │   ├── gcd.py │   ├── generate_strobogrammtic.py +│   ├── __init__.py │   ├── is_strobogrammatic.py +│   ├── next_bigger.py │   ├── next_perfect_square.py │   ├── nth_digit.py +│   ├── prime_check.py │   ├── primes_sieve_of_eratosthenes.py -│   ├── prime_test.py │   ├── pythagoras.py │   ├── rabin_miller.py │   ├── rsa.py -│   └── sqrt_precision_factor.py +│   ├── sqrt_precision_factor.py +│   └── summing_digits.py ├── matrix │   ├── bomb_enemy.py │   ├── copy_transform.py @@ -133,54 +160,80 @@ │   ├── search_in_sorted_matrix.py │   ├── sparse_dot_vector.py │   ├── sparse_mul.py -│   └── spiral_traversal.py +│   ├── spiral_traversal.py +│   └── sudoku_validator.py ├── queues │   ├── __init__.py │   ├── max_sliding_window.py │   ├── moving_average.py -│   ├── __pycache__ -│   │   └── __init__.cpython-36.pyc +│   ├── priority_queue.py │   ├── queue.py │   ├── reconstruct_queue.py │   └── zigzagiterator.py -├── README_CN.md -├── README.md ├── search │   ├── binary_search.py +│   ├── find_min_rotate.py │   ├── first_occurance.py -│   └── last_occurance.py +│   ├── __init__.py +│   ├── jump_search.py +│   ├── last_occurance.py +│   ├── linear_search.py +│   ├── search_insert.py +│   ├── search_range.py +│   ├── search_rotate.py +│   └── two_sum.py ├── set │   ├── randomized_set.py │   └── set_covering.py ├── sort +│   ├── bitonic_sort.py +│   ├── bogo_sort.py │   ├── bubble_sort.py +│   ├── bucket_sort.py +│   ├── cocktail_shaker_sort.py │   ├── comb_sort.py │   ├── counting_sort.py +│   ├── gnome_sort.py │   ├── heap_sort.py +│   ├── __init__.py │   ├── insertion_sort.py │   ├── meeting_rooms.py │   ├── merge_sort.py │   ├── quick_sort.py +│   ├── radix_sort.py │   ├── selection_sort.py +│   ├── shell_sort.py │   ├── sort_colors.py -│   ├── topsort.py +│   ├── top_sort.py │   └── wiggle_sort.py ├── stack │   ├── __init__.py +│   ├── is_consecutive.py +│   ├── is_sorted.py │   ├── longest_abs_path.py +│   ├── ordered_stack.py +│   ├── remove_min.py │   ├── simplify_path.py │   ├── stack.py +│   ├── stutter.py +│   ├── switch_pairs.py │   └── valid_parenthesis.py ├── strings │   ├── add_binary.py │   ├── breaking_bad.py │   ├── decode_string.py +│   ├── delete_reoccurring.py +│   ├── domain_extractor.py │   ├── encode_decode.py +│   ├── fizzbuzz.py │   ├── group_anagrams.py +│   ├── __init__.py │   ├── int_to_roman.py │   ├── is_palindrome.py +│   ├── is_rotated.py │   ├── license_number.py │   ├── make_sentence.py +│   ├── merge_string_checker.py │   ├── multiply_strings.py │   ├── one_edit_distance.py │   ├── rabin_karp.py @@ -188,20 +241,28 @@ │   ├── reverse_vowel.py │   ├── reverse_words.py │   ├── roman_to_int.py +│   ├── strip_url_params.py +│   ├── validate_coordinates.py │   └── word_squares.py -├── tmp -│   └── temporary.md ├── tree +│   ├── avl +│   │   ├── avl.py +│   │   └── __init__.py │   ├── binary_tree_paths.py │   ├── bintree2list.py │   ├── bst │   │   ├── array2bst.py │   │   ├── bst_closest_value.py │   │   ├── BSTIterator.py +│   │   ├── bst.py +│   │   ├── count_left_node.py │   │   ├── delete_node.py +│   │   ├── depth_sum.py +│   │   ├── height.py │   │   ├── is_bst.py │   │   ├── kth_smallest.py │   │   ├── lowest_common_ancestor.py +│   │   ├── num_empty.py │   │   ├── predecessor.py │   │   ├── serialize_deserialize.py │   │   ├── successor.py @@ -219,8 +280,8 @@ │   ├── path_sum2.py │   ├── path_sum.py │   ├── pretty_print.py -│   ├── rbtree -│   │   └── rbtree.py +│   ├── red_black_tree +│   │   └── red_black_tree.py │   ├── same_tree.py │   ├── segment_tree │   │   └── segment_tree.py @@ -232,10 +293,8 @@ │   └── trie │   ├── add_and_search.py │   └── trie.py -├── tree.md └── union-find └── count_islands.py -28 directories, 206 files - +27 directories, 267 files ``` From ffe1c210b1e5687c6f996297b91d74abb5f82478 Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Thu, 7 Jun 2018 20:28:35 +0530 Subject: [PATCH 060/302] add PyPI badge to READMEs (#334) * add PyPI badge to READMEs * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + 5 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 69b550d4d..7fcf88c61 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) [![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) diff --git a/README_CN.md b/README_CN.md index 0f5793e27..72bdaea3c 100644 --- a/README_CN.md +++ b/README_CN.md @@ -2,6 +2,7 @@ [English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) [![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) diff --git a/README_GE.md b/README_GE.md index dc493bc3a..510635888 100644 --- a/README_GE.md +++ b/README_GE.md @@ -2,6 +2,7 @@ [English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) [![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) diff --git a/README_JP.md b/README_JP.md index 15d244c2f..0bb40aa9e 100644 --- a/README_JP.md +++ b/README_JP.md @@ -2,6 +2,7 @@ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) [![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) diff --git a/README_KR.md b/README_KR.md index 678798851..20efba9af 100644 --- a/README_KR.md +++ b/README_KR.md @@ -2,6 +2,7 @@ [English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) [![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) From f9f8746993576d1899493a7f0ec8a4fe6765e46b Mon Sep 17 00:00:00 2001 From: Han SangWook <9967han@naver.com> Date: Fri, 8 Jun 2018 03:03:09 +0900 Subject: [PATCH 061/302] Created pancake_sort.py in algorithms/sorts (#336) * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_sort.py * Create pancake_sort.py * Update __init__.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/pancake_sort.py | 25 +++++++++++++++++++++++++ tests/test_sort.py | 5 +++++ 8 files changed, 36 insertions(+) create mode 100644 algorithms/sort/pancake_sort.py diff --git a/README.md b/README.md index 7fcf88c61..af1f9c51a 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,7 @@ If you want to uninstall algorithms, it is as simple as: - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) diff --git a/README_CN.md b/README_CN.md index 72bdaea3c..f729b8861 100644 --- a/README_CN.md +++ b/README_CN.md @@ -221,6 +221,7 @@ pip3 uninstall -y algorithms - [insertion_sort:插入排序](algorithms/sort/insertion_sort.py) - [meeting_rooms:会议室](algorithms/sort/meeting_rooms.py) - [merge_sort:归并排序](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) - [quick_sort:快速排序](algorithms/sort/quick_sort.py) - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort:选择排序](algorithms/sort/selection_sort.py) diff --git a/README_GE.md b/README_GE.md index 510635888..c6b57bf2c 100644 --- a/README_GE.md +++ b/README_GE.md @@ -242,6 +242,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) diff --git a/README_JP.md b/README_JP.md index 0bb40aa9e..ffc546a68 100644 --- a/README_JP.md +++ b/README_JP.md @@ -236,6 +236,7 @@ if __name__ == "__main__": - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) diff --git a/README_KR.md b/README_KR.md index 20efba9af..8a30c02f2 100644 --- a/README_KR.md +++ b/README_KR.md @@ -232,6 +232,7 @@ if __name__ == "__main__": - [insertion_sort](algorithms/sort/insertion_sort.py) - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index a7dba9a16..19648fdcd 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -6,6 +6,7 @@ from .heap_sort import * from .insertion_sort import * from .merge_sort import * +from .pancake_sort import * from .quick_sort import * from .selection_sort import * from .top_sort import * diff --git a/algorithms/sort/pancake_sort.py b/algorithms/sort/pancake_sort.py new file mode 100644 index 000000000..19725c043 --- /dev/null +++ b/algorithms/sort/pancake_sort.py @@ -0,0 +1,25 @@ +def pancake_sort(arr): + """ + Pancake_sort + Sorting a given array + mutation of selection sort + + reference: https://www.geeksforgeeks.org/pancake-sorting/ + + Overall time complexity : O(N^2) + """ + + len_arr = len(arr) + if len_arr <= 1: + return arr + for cur in range(len(arr), 1, -1): + #Finding index of maximum number in arr + index_max = arr.index(max(arr[0:cur])) + if index_max+1 != cur: + #Needs moving + if index_max != 0: + #reverse from 0 to index_max + arr[:index_max+1] = reversed(arr[:index_max+1]) + # Reverse list + arr[:cur] = reversed(arr[:cur]) + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index 7d8ea8a9b..3615f1911 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -7,6 +7,7 @@ max_heap_sort, min_heap_sort, insertion_sort, merge_sort, + pancake_sort, quick_sort, selection_sort, bucket_sort, @@ -60,6 +61,10 @@ def test_merge_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], merge_sort([1, 5, 65, 23, 57, 1232])) + def test_pancake_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + pancake_sort([1, 5, 65, 23, 57, 1232])) + def test_quick_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], quick_sort([1, 5, 65, 23, 57, 1232])) From 409ae684a7403a7a7a3a60c260a75b9909fdcbaa Mon Sep 17 00:00:00 2001 From: Han SangWook <9967han@naver.com> Date: Fri, 8 Jun 2018 15:15:38 +0900 Subject: [PATCH 062/302] Created cycle_sort.py in algorithms/sort (#338) * Create cycle_sort.py * Update test_sort.py * Update __init__.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/cycle_sort.py | 46 +++++++++++++++++++++++++++++++++++ tests/test_sort.py | 5 ++++ 8 files changed, 57 insertions(+) create mode 100644 algorithms/sort/cycle_sort.py diff --git a/README.md b/README.md index af1f9c51a..8cbf568ed 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,7 @@ If you want to uninstall algorithms, it is as simple as: - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) diff --git a/README_CN.md b/README_CN.md index f729b8861..43032d92b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -216,6 +216,7 @@ pip3 uninstall -y algorithms - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort:梳排序](algorithms/sort/comb_sort.py) - [counting_sort:计数排序](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort:堆排序](algorithms/sort/heap_sort.py) - [insertion_sort:插入排序](algorithms/sort/insertion_sort.py) diff --git a/README_GE.md b/README_GE.md index c6b57bf2c..529ce79cb 100644 --- a/README_GE.md +++ b/README_GE.md @@ -237,6 +237,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) diff --git a/README_JP.md b/README_JP.md index ffc546a68..f47bec7ab 100644 --- a/README_JP.md +++ b/README_JP.md @@ -231,6 +231,7 @@ if __name__ == "__main__": - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) diff --git a/README_KR.md b/README_KR.md index 8a30c02f2..848754109 100644 --- a/README_KR.md +++ b/README_KR.md @@ -227,6 +227,7 @@ if __name__ == "__main__": - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index 19648fdcd..fceb3bd22 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -3,6 +3,7 @@ from .bubble_sort import * from .comb_sort import * from .counting_sort import * +from .cycle_sort import * from .heap_sort import * from .insertion_sort import * from .merge_sort import * diff --git a/algorithms/sort/cycle_sort.py b/algorithms/sort/cycle_sort.py new file mode 100644 index 000000000..6e512c924 --- /dev/null +++ b/algorithms/sort/cycle_sort.py @@ -0,0 +1,46 @@ +def cycle_sort(arr): + """ + cycle_sort + This is based on the idea that the permutations to be sorted + can be decomposed into cycles, + and the results can be individually sorted by cycling. + + reference: https://en.wikipedia.org/wiki/Cycle_sort + + Average time complexity : O(N^2) + Worst case time complexity : O(N^2) + """ + len_arr = len(arr) + # Finding cycle to rotate. + for cur in range(len_arr - 1): + item = arr[cur] + + # Finding an indx to put items in. + index = cur + for i in range(cur + 1, len_arr): + if arr[i] < item: + index += 1 + + # Case of there is not a cycle + if index == cur: + continue + + # Putting the item immediately right after the duplicate item or on the right. + while item == arr[index]: + index += 1 + arr[index], item = item, arr[index] + + # Rotating the remaining cycle. + while index != cur: + + # Finding where to put the item. + index = cur + for i in range(cur + 1, len_arr): + if arr[i] < item: + index += 1 + + # After item is duplicated, put it in place or put it there. + while item == arr[index]: + index += 1 + arr[index], item = item, arr[index] + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index 3615f1911..d77f086d9 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -4,6 +4,7 @@ bubble_sort, comb_sort, counting_sort, + cycle_sort, max_heap_sort, min_heap_sort, insertion_sort, merge_sort, @@ -47,6 +48,10 @@ def test_counting_sort(self): self.assertEqual([-1232, -65, -57, -23, -5, -1], counting_sort([-1, -5, -65, -23, -57, -1232])) + def test_cycle_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + cycle_sort([1, 5, 65, 23, 57, 1232])) + def test_heap_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], max_heap_sort([1, 5, 65, 23, 57, 1232])) From 5e08ff9c52b56952149dfa1e54ab063bf401a0a9 Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Fri, 8 Jun 2018 15:17:18 +0900 Subject: [PATCH 063/302] Added simulation features in insertion & selection sorts (#333) * Added simulation feature * Added simulation feature * Update insertion_sort.py * Update selection_sort.py * Update insertion_sort.py * Update selection_sort.py * Update bubble_sort.py * Update bubble_sort.py * Update insertion_sort.py * Update selection_sort.py --- algorithms/sort/bubble_sort.py | 6 ++++-- algorithms/sort/insertion_sort.py | 12 +++++++++++- algorithms/sort/selection_sort.py | 12 +++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/algorithms/sort/bubble_sort.py b/algorithms/sort/bubble_sort.py index 63c6c4f14..76c9816fa 100644 --- a/algorithms/sort/bubble_sort.py +++ b/algorithms/sort/bubble_sort.py @@ -17,8 +17,9 @@ def swap(i, j): n = len(arr) swapped = True + iteration = 0 if simulation: - print(arr) + print("iteration",iteration,":",*arr) while swapped: swapped = False @@ -27,6 +28,7 @@ def swap(i, j): swap(i - 1, i) swapped = True if simulation: - print(arr) + iteration = iteration + 1 + print("iteration",iteration,":",*arr) return arr diff --git a/algorithms/sort/insertion_sort.py b/algorithms/sort/insertion_sort.py index f6d1ce3c9..06c86228d 100644 --- a/algorithms/sort/insertion_sort.py +++ b/algorithms/sort/insertion_sort.py @@ -1,15 +1,25 @@ -def insertion_sort(arr): +def insertion_sort(arr, simulation=False): """ Insertion Sort Complexity: O(n^2) """ + + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + for i in range(len(arr)): cursor = arr[i] pos = i + while pos > 0 and arr[pos - 1] > cursor: # Swap the number down the list arr[pos] = arr[pos - 1] pos = pos - 1 # Break and do the final swap arr[pos] = cursor + + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) return arr diff --git a/algorithms/sort/selection_sort.py b/algorithms/sort/selection_sort.py index c5db918dd..f6d535225 100644 --- a/algorithms/sort/selection_sort.py +++ b/algorithms/sort/selection_sort.py @@ -1,13 +1,23 @@ -def selection_sort(arr): +def selection_sort(arr, simulation=False): """ Selection Sort Complexity: O(n^2) """ + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + for i in range(len(arr)): minimum = i + for j in range(i + 1, len(arr)): # "Select" the correct value if arr[j] < arr[minimum]: minimum = j arr[minimum], arr[i] = arr[i], arr[minimum] + + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) + return arr From 65f9a6dc851f98c9e3f9600714bc67040216a9ff Mon Sep 17 00:00:00 2001 From: herinckc <31827186+herinckc@users.noreply.github.com> Date: Fri, 8 Jun 2018 08:08:01 -0700 Subject: [PATCH 064/302] refactored variable names (#340) * fixed all relevant camelcase names I've seen up to 'graph' folder * fixed all instances of camelcase I noted up to 'linkedlist' folder * removed all noted camelcase up to queues folder * removed any camelcase I saw up through 'search' folder and changed 'occurance' to 'occurrence' * removed all noted camelcase up to 'trees' folder and changed 'dictionarys' to 'dictionaries' * removed all noted camelcase from 'algorithms' folder and made minor spelling changes throughout * changed setup back to setUp in relevent bst-related algos * fixed the missed curr_len in longest_abs_path.py --- algorithms/arrays/max_ones_index.py | 2 +- algorithms/calculator/math_parser.py | 2 +- algorithms/dfs/sudoku_solver.py | 2 +- algorithms/dp/fib.py | 2 +- ...py => check_digraph_strongly_connected.py} | 0 ...> path_between_two_vertices_in_digraph.py} | 0 algorithms/maths/base_conversion.py | 4 +-- algorithms/search/__init__.py | 4 +-- ...first_occurance.py => first_occurrence.py} | 2 +- .../{last_occurance.py => last_occurrence.py} | 2 +- algorithms/stack/longest_abs_path.py | 14 ++++----- algorithms/strings/make_sentence.py | 6 ++-- .../{bintree2list.py => bin_tree_to_list.py} | 12 ++++---- .../bst/{array2bst.py => array_to_bst.py} | 6 ++-- algorithms/tree/longest_consecutive.py | 14 ++++----- .../tree/red_black_tree/red_black_tree.py | 2 +- algorithms/tree/segment_tree/segment_tree.py | 6 ++-- tests/test_maths.py | 14 ++++----- tests/test_search.py | 30 +++++++++---------- 19 files changed, 62 insertions(+), 62 deletions(-) rename algorithms/graph/{checkDiGraphStronglyConnected.py => check_digraph_strongly_connected.py} (100%) rename algorithms/graph/{pathBetweenTwoVerticesInDiGraph.py => path_between_two_vertices_in_digraph.py} (100%) rename algorithms/search/{first_occurance.py => first_occurrence.py} (92%) rename algorithms/search/{last_occurance.py => last_occurrence.py} (92%) rename algorithms/tree/{bintree2list.py => bin_tree_to_list.py} (78%) rename algorithms/tree/bst/{array2bst.py => array_to_bst.py} (75%) diff --git a/algorithms/arrays/max_ones_index.py b/algorithms/arrays/max_ones_index.py index bee1f760d..40abdf505 100644 --- a/algorithms/arrays/max_ones_index.py +++ b/algorithms/arrays/max_ones_index.py @@ -40,4 +40,4 @@ def max_ones_index(arr): if n - prev_prev_zero > max_count: max_index = prev_zero - return max_index \ No newline at end of file + return max_index diff --git a/algorithms/calculator/math_parser.py b/algorithms/calculator/math_parser.py index 830d71794..a1d0e0ba5 100644 --- a/algorithms/calculator/math_parser.py +++ b/algorithms/calculator/math_parser.py @@ -144,4 +144,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/algorithms/dfs/sudoku_solver.py b/algorithms/dfs/sudoku_solver.py index 4f3c27530..387cdcaea 100644 --- a/algorithms/dfs/sudoku_solver.py +++ b/algorithms/dfs/sudoku_solver.py @@ -107,4 +107,4 @@ def test_sudoku_solver(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/algorithms/dp/fib.py b/algorithms/dp/fib.py index 3ba4c5e3a..765ee2f34 100644 --- a/algorithms/dp/fib.py +++ b/algorithms/dp/fib.py @@ -70,4 +70,4 @@ def fib_iter(n): return sum # => 354224848179261915075 -# print(fib_iter(100)) \ No newline at end of file +# print(fib_iter(100)) diff --git a/algorithms/graph/checkDiGraphStronglyConnected.py b/algorithms/graph/check_digraph_strongly_connected.py similarity index 100% rename from algorithms/graph/checkDiGraphStronglyConnected.py rename to algorithms/graph/check_digraph_strongly_connected.py diff --git a/algorithms/graph/pathBetweenTwoVerticesInDiGraph.py b/algorithms/graph/path_between_two_vertices_in_digraph.py similarity index 100% rename from algorithms/graph/pathBetweenTwoVerticesInDiGraph.py rename to algorithms/graph/path_between_two_vertices_in_digraph.py diff --git a/algorithms/maths/base_conversion.py b/algorithms/maths/base_conversion.py index 1ea31e3be..cc3b62cbb 100644 --- a/algorithms/maths/base_conversion.py +++ b/algorithms/maths/base_conversion.py @@ -8,7 +8,7 @@ import string -def int2base(n, base): +def int_to_base(n, base): """ :type n: int :type base: int @@ -31,7 +31,7 @@ def int2base(n, base): return res[::-1] -def base2int(s, base): +def base_to_int(s, base): """ Note : You can use int() built-in function instread of this. :type s: str diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index ec3a78326..8304059e9 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -1,6 +1,6 @@ from .binary_search import * -from .first_occurance import * -from .last_occurance import * +from .first_occurrence import * +from .last_occurrence import * from .linear_search import * from .search_insert import * from .two_sum import * diff --git a/algorithms/search/first_occurance.py b/algorithms/search/first_occurrence.py similarity index 92% rename from algorithms/search/first_occurance.py rename to algorithms/search/first_occurrence.py index addf17058..86dc89ced 100644 --- a/algorithms/search/first_occurance.py +++ b/algorithms/search/first_occurrence.py @@ -3,7 +3,7 @@ # Approach- Binary Search # T(n)- O(log n) # -def first_occurance(array, query): +def first_occurrence(array, query): lo, hi = 0, len(array) - 1 while lo <= hi: mid = (lo + hi) // 2 diff --git a/algorithms/search/last_occurance.py b/algorithms/search/last_occurrence.py similarity index 92% rename from algorithms/search/last_occurance.py rename to algorithms/search/last_occurrence.py index b8ee4fa62..345b42395 100644 --- a/algorithms/search/last_occurance.py +++ b/algorithms/search/last_occurrence.py @@ -3,7 +3,7 @@ # Approach- Binary Search # T(n)- O(log n) # -def last_occurance(array, query): +def last_occurrence(array, query): lo, hi = 0, len(array) - 1 while lo <= hi: mid = (hi + lo) // 2 diff --git a/algorithms/stack/longest_abs_path.py b/algorithms/stack/longest_abs_path.py index 64c7a67af..67aad5a6a 100644 --- a/algorithms/stack/longest_abs_path.py +++ b/algorithms/stack/longest_abs_path.py @@ -38,7 +38,7 @@ def length_longest_path(input): :type input: str :rtype: int """ - currlen, maxlen = 0, 0 # running length and max length + curr_len, max_len = 0, 0 # running length and max length stack = [] # keep track of the name length for s in input.split('\n'): print("---------") @@ -46,16 +46,16 @@ def length_longest_path(input): depth = s.count('\t') # the depth of current dir or file print("depth: ", depth) print("stack: ", stack) - print("curlen: ", currlen) + print("curlen: ", curr_len) while len(stack) > depth: # go back to the correct depth - currlen -= stack.pop() + curr_len -= stack.pop() stack.append(len(s.strip('\t'))+1) # 1 is the length of '/' - currlen += stack[-1] # increase current length + curr_len += stack[-1] # increase current length print("stack: ", stack) - print("curlen: ", currlen) + print("curlen: ", curr_len) if '.' in s: # update maxlen only when it is a file - maxlen = max(maxlen, currlen-1) # -1 is to minus one '/' - return maxlen + max_len = max(max_len, curr_len-1) # -1 is to minus one '/' + return max_len st= "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdirectory1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" st2 = "a\n\tb1\n\t\tf1.txt\n\taaaaa\n\t\tf2.txt" diff --git a/algorithms/strings/make_sentence.py b/algorithms/strings/make_sentence.py index 8e6cb5b3b..2b7bcf79f 100644 --- a/algorithms/strings/make_sentence.py +++ b/algorithms/strings/make_sentence.py @@ -15,13 +15,13 @@ count = 0 -def make_sentence(str_piece, dictionarys): +def make_sentence(str_piece, dictionaries): global count if len(str_piece) == 0: return True for i in range(0, len(str_piece)): prefix, suffix = str_piece[0:i], str_piece[i:] - if prefix in dictionarys: - if suffix in dictionarys or make_sentence(suffix, dictionarys): + if prefix in dictionaries: + if suffix in dictionaries or make_sentence(suffix, dictionaries): count += 1 return True diff --git a/algorithms/tree/bintree2list.py b/algorithms/tree/bin_tree_to_list.py similarity index 78% rename from algorithms/tree/bintree2list.py rename to algorithms/tree/bin_tree_to_list.py index 091295444..d23834b12 100644 --- a/algorithms/tree/bintree2list.py +++ b/algorithms/tree/bin_tree_to_list.py @@ -4,28 +4,28 @@ def __init__(self, val = 0): self.left = None self.right = None -def bintree2list(root): +def bin_tree_to_list(root): """ type root: root class """ if not root: return root - root = bintree2list_util(root) + root = bin_tree_to_list_util(root) while root.left: root = root.left return root -def bintree2list_util(root): +def bin_tree_to_list_util(root): if not root: return root if root.left: - left = bintree2list_util(root.left) + left = bin_tree_to_list_util(root.left) while left.right: left = left.right left.right = root root.left = left if root.right: - right = bintree2list_util(root.right) + right = bin_tree_to_list_util(root.right) while right.left: right = right.left right.left = root @@ -45,5 +45,5 @@ def print_tree(root): tree.left.right = Node(30) tree.right.left = Node(36) -head = bintree2list(tree) +head = bin_tree_to_list(tree) print_tree(head) diff --git a/algorithms/tree/bst/array2bst.py b/algorithms/tree/bst/array_to_bst.py similarity index 75% rename from algorithms/tree/bst/array2bst.py rename to algorithms/tree/bst/array_to_bst.py index 62fe5b9b7..7ca5cf943 100644 --- a/algorithms/tree/bst/array2bst.py +++ b/algorithms/tree/bst/array_to_bst.py @@ -11,11 +11,11 @@ def __init__(self, x): self.right = None -def array2bst(nums): +def array_to_bst(nums): if not nums: return None mid = len(nums)//2 node = TreeNode(nums[mid]) - node.left = array2bst(nums[:mid]) - node.right = array2bst(nums[mid+1:]) + node.left = array_to_bst(nums[:mid]) + node.right = array_to_bst(nums[mid+1:]) return node diff --git a/algorithms/tree/longest_consecutive.py b/algorithms/tree/longest_consecutive.py index fde962c26..4fd809a1c 100644 --- a/algorithms/tree/longest_consecutive.py +++ b/algorithms/tree/longest_consecutive.py @@ -32,18 +32,18 @@ def longest_consecutive(root): """ if not root: return 0 - maxlen = 0 - dfs(root, 0, root.val, maxlen) - return maxlen + max_len = 0 + dfs(root, 0, root.val, max_len) + return max_len -def dfs(root, cur, target, maxlen): +def dfs(root, cur, target, max_len): if not root: return if root.val == target: cur += 1 else: cur = 1 - maxlen = max(cur, maxlen) - dfs(root.left, cur, root.val+1, maxlen) - dfs(root.right, cur, root.val+1, maxlen) + max_len = max(cur, max_len) + dfs(root.left, cur, root.val+1, max_len) + dfs(root.right, cur, root.val+1, max_len) diff --git a/algorithms/tree/red_black_tree/red_black_tree.py b/algorithms/tree/red_black_tree/red_black_tree.py index 15114e082..33fb6af4a 100644 --- a/algorithms/tree/red_black_tree/red_black_tree.py +++ b/algorithms/tree/red_black_tree/red_black_tree.py @@ -202,7 +202,7 @@ def delete(self, node): node_min.left = node.left node_min.left.parent = node_min node_min.color = node.color - # when node is black ,then need to fix it with 4 cases + # when node is black, then need to fix it with 4 cases if node_color == 0: self.delete_fixup(temp_node) diff --git a/algorithms/tree/segment_tree/segment_tree.py b/algorithms/tree/segment_tree/segment_tree.py index de62b6b42..2bf51966f 100644 --- a/algorithms/tree/segment_tree/segment_tree.py +++ b/algorithms/tree/segment_tree/segment_tree.py @@ -10,12 +10,12 @@ def __init__(self,arr,function): self.fn = function self.maketree(0,0,len(arr)-1) - def maketree(self,i,l,r): + def make_tree(self,i,l,r): if l==r: self.segment[i] = self.arr[l] elif l Date: Sun, 10 Jun 2018 05:23:51 +0900 Subject: [PATCH 065/302] Update README_JP.md (#341) --- README_JP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_JP.md b/README_JP.md index f47bec7ab..b81f9cea6 100644 --- a/README_JP.md +++ b/README_JP.md @@ -38,7 +38,7 @@ Python 3で開発された簡単で明確なデータ構造とアルゴリズム $ pip3 install git+https://github.com/keon/algorithms -Pythonファイルを作成してテストを行うことができます:(例:「sort」の「merge_sort」を使用) +Pythonファイルを作成してテストを実行することができます:(例:「sort」の「merge_sort」を使用) ```python3 from sort import merge_sort From 32b20e2e4a46fd580d23448b072c81b5485ed050 Mon Sep 17 00:00:00 2001 From: Victor Encarnacion Date: Sat, 9 Jun 2018 13:45:06 -0700 Subject: [PATCH 066/302] Add decimal_to_binary_ip.py (#339) * Add decimal_to_binary_ip.py Converts dotted_decimal ip address to binary ip address. * Include tests for decimal_to_binary_ip Some tests cases for decimal_to_binary_ip function. * Fix TestDecimalToBinaryIP method name changed method from test_int2base to test_decimal_to_binary_ip * Import decimal_to_binary_ip Added decimal_to_binary_ip to imports * Update README.md Add to decimal_to_binary_ip * resolve conflicts in test_maths --- README.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/decimal_to_binary_ip.py | 27 ++++++++++++++++++++++++ tests/test_maths.py | 19 +++++++++++++++-- 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 algorithms/maths/decimal_to_binary_ip.py diff --git a/README.md b/README.md index 8cbf568ed..c954e5fd7 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,7 @@ If you want to uninstall algorithms, it is as simple as: - [maths](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) + - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 2bf44a78f..543d8d355 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -1,4 +1,5 @@ from .base_conversion import * +from .decimal_to_binary_ip import * from .extended_gcd import * from .factorial import * from .gcd import * diff --git a/algorithms/maths/decimal_to_binary_ip.py b/algorithms/maths/decimal_to_binary_ip.py new file mode 100644 index 000000000..579e3402a --- /dev/null +++ b/algorithms/maths/decimal_to_binary_ip.py @@ -0,0 +1,27 @@ +""" +Given an ip address in dotted-decimal representation, determine the +binary representation. For example, +decimal_to_binary(255.0.0.5) returns 11111111.00000000.00000000.00000101 +accepts string +returns string +""" + +def decimal_to_binary_util(val): + bits = [128, 64, 32, 16, 8, 4, 2, 1] + val = int(val) + binary_rep = '' + for bit in bits: + if val >= bit: + binary_rep += str(1) + val -= bit + else: + binary_rep += str(0) + + return binary_rep + +def decimal_to_binary_ip(ip): + values = ip.split('.') + binary_list = [] + for val in values: + binary_list.append(decimal_to_binary_util(val)) + return '.'.join(binary_list) diff --git a/tests/test_maths.py b/tests/test_maths.py index ece9ab7e7..1514907fe 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,5 +1,6 @@ from algorithms.maths import ( int_to_base, base_to_int, + decimal_to_binary_ip, extended_gcd, factorial, factorial_recur, gcd, lcm, @@ -25,15 +26,29 @@ class TestBaseConversion(unittest.TestCase): unittest {[type]} -- [description] """ - def test_int2base(self): + def test_int_to_base(self): self.assertEqual("101", int_to_base(5, 2)) self.assertEqual("0", int_to_base(0, 2)) self.assertEqual("FF", int_to_base(255, 16)) - def test_base2int(self): + def test_base_to_int(self): self.assertEqual(5, base_to_int("101", 2)) self.assertEqual(0, base_to_int("0", 2)) self.assertEqual(255, base_to_int("FF", 16)) + + +class TestDecimalToBinaryIP(unittest.TestCase): + """ + Test for the file decimal_to_binary_ip.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_decimal_to_binary_ip(self): + self.assertEqual("00000000.00000000.00000000.00000000", decimal_to_binary_ip("0.0.0.0")) + self.assertEqual("11111111.11111111.11111111.11111111", decimal_to_binary_ip("255.255.255.255")) + self.assertEqual("11000000.10101000.00000000.00000001", decimal_to_binary_ip("192.168.0.1")) class TestExtendedGcd(unittest.TestCase): From 601202b4bdf4044f7f107ed4a584dc0703f3703d Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Sun, 10 Jun 2018 19:27:33 +0900 Subject: [PATCH 067/302] Created BFS maze_search.py and test case (#343) * Create maze_search.py * Create test_bfs.py * Create __init__.py * Update README.md * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_bfs.py * Update maze_search.py * Update __init__.py * Update test_bfs.py * Update test_bfs.py * Update maze_search.py * Update maze_search.py * Update test_bfs.py * Update maze_search.py * Create top_1.py * Create trimmean.py * Delete trimmean.py * Delete top_1.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/bfs/__init__.py | 3 +++ algorithms/bfs/maze_search.py | 33 +++++++++++++++++++++++++++++++++ tests/test_bfs.py | 18 ++++++++++++++++++ 8 files changed, 59 insertions(+) create mode 100644 algorithms/bfs/__init__.py create mode 100644 algorithms/bfs/maze_search.py create mode 100644 tests/test_bfs.py diff --git a/README.md b/README.md index c954e5fd7..f1497ca16 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ If you want to uninstall algorithms, it is as simple as: - [subsets](algorithms/backtrack/subsets.py) - [subsets_unique](algorithms/backtrack/subsets_unique.py) - [bfs](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder](algorithms/bfs/word_ladder.py) - [bit](algorithms/bit) diff --git a/README_CN.md b/README_CN.md index 43032d92b..efff430ed 100644 --- a/README_CN.md +++ b/README_CN.md @@ -104,6 +104,7 @@ pip3 uninstall -y algorithms - [subsets:子集](algorithms/backtrack/subsets.py) - [subsets_unique:唯一子集](algorithms/backtrack/subsets_unique.py) - [bfs:广度优先搜索](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) - [shortest_distance_from_all_buildings:所有建筑物的最短路径:](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder:词语阶梯](algorithms/bfs/word_ladder.py) - [bit:位操作](algorithms/bit) diff --git a/README_GE.md b/README_GE.md index 529ce79cb..afdcc322d 100644 --- a/README_GE.md +++ b/README_GE.md @@ -94,6 +94,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [subsets](algorithms/backtrack/subsets.py) - [subsets_unique](algorithms/backtrack/subsets_unique.py) - [bfs](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder](algorithms/bfs/word_ladder.py) - [bit](algorithms/bit) diff --git a/README_JP.md b/README_JP.md index b81f9cea6..d3603b76f 100644 --- a/README_JP.md +++ b/README_JP.md @@ -88,6 +88,7 @@ if __name__ == "__main__": - [subsets](algorithms/backtrack/subsets.py) - [subsets_unique](algorithms/backtrack/subsets_unique.py) - [bfs : 幅優先探索](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder](algorithms/bfs/word_ladder.py) - [bit : ビット](algorithms/bit) diff --git a/README_KR.md b/README_KR.md index 848754109..e5b528389 100644 --- a/README_KR.md +++ b/README_KR.md @@ -87,6 +87,7 @@ if __name__ == "__main__": - [subsets](algorithms/backtrack/subsets.py) - [subsets_unique](algorithms/backtrack/subsets_unique.py) - [bfs : 너비 우선 탐색](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder](algorithms/bfs/word_ladder.py) - [bit : 비트](algorithms/bit) diff --git a/algorithms/bfs/__init__.py b/algorithms/bfs/__init__.py new file mode 100644 index 000000000..b3d3b0c6a --- /dev/null +++ b/algorithms/bfs/__init__.py @@ -0,0 +1,3 @@ +from .maze_search import * +from .shortest_distance_from_all_buildings import * +from .word_ladder import * diff --git a/algorithms/bfs/maze_search.py b/algorithms/bfs/maze_search.py new file mode 100644 index 000000000..efa65c357 --- /dev/null +++ b/algorithms/bfs/maze_search.py @@ -0,0 +1,33 @@ +''' +BFS time complexity : O(|E|) +BFS space complexity : O(|V|) + +do BFS from (0,0) of the grid and get the minimum number of steps needed to get to the lower right column + +only step on the columns whose value is 1 + +if there is no path, it returns -1 +''' + +def maze_search(grid): + dx = [0,0,-1,1] + dy = [-1,1,0,0] + n = len(grid) + m = len(grid[0]) + q = [(0,0,0)] + visit = [[0]*m for _ in range(n)] + if grid[0][0] == 0: + return -1 + visit[0][0] = 1 + while q: + i, j, step = q.pop(0) + if i == n-1 and j == m-1: + return step + for k in range(4): + x = i + dx[k] + y = j + dy[k] + if x>=0 and x=0 and y Date: Sun, 10 Jun 2018 19:29:03 +0900 Subject: [PATCH 068/302] top_1.py & trimmean.py created (#345) * Create top_1.py * Create trimmean.py * Rename top_1.py to algorithms/arrays/top_1.py * Rename trimmean.py to algorithms/arrays/trimmean.py * Update __init__.py * Update README.md * Update README_CN.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_array.py * Update test_array.py * Update test_array.py --- README.md | 2 ++ README_CN.md | 2 ++ README_GE.md | 2 ++ README_JP.md | 2 ++ README_KR.md | 2 ++ algorithms/arrays/__init__.py | 2 ++ algorithms/arrays/top_1.py | 32 ++++++++++++++++++++++++++++++++ algorithms/arrays/trimmean.py | 22 ++++++++++++++++++++++ tests/test_array.py | 18 +++++++++++++++++- 9 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 algorithms/arrays/top_1.py create mode 100644 algorithms/arrays/trimmean.py diff --git a/README.md b/README.md index f1497ca16..18858ce8e 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ If you want to uninstall algorithms, it is as simple as:    - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack](algorithms/backtrack) diff --git a/README_CN.md b/README_CN.md index efff430ed..db759e9f0 100644 --- a/README_CN.md +++ b/README_CN.md @@ -85,6 +85,8 @@ pip3 uninstall -y algorithms - [rotate:反转数组](algorithms/arrays/rotate.py) - [summarize_ranges:数组范围](algorithms/arrays/summarize_ranges.py) - [three_sum:三数和为零](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) - [two_sum:两数和](algorithms/arrays/two_sum.py) - [move_zeros: 0后置问题](algorithms/arrays/move_zeros.py) - [backtrack:回溯](algorithms/backtrack) diff --git a/README_GE.md b/README_GE.md index afdcc322d..f0a48ca9b 100644 --- a/README_GE.md +++ b/README_GE.md @@ -75,6 +75,8 @@ Um das Projekt zu deinstallieren tippen Sie folgendes:    - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack](algorithms/backtrack) diff --git a/README_JP.md b/README_JP.md index d3603b76f..d50f01253 100644 --- a/README_JP.md +++ b/README_JP.md @@ -69,6 +69,8 @@ if __name__ == "__main__":    - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack : バックトラッキング](algorithms/backtrack) diff --git a/README_KR.md b/README_KR.md index e5b528389..dd78fa0d9 100644 --- a/README_KR.md +++ b/README_KR.md @@ -68,6 +68,8 @@ if __name__ == "__main__":    - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) - [backtrack : 백트래킹](algorithms/backtrack) diff --git a/algorithms/arrays/__init__.py b/algorithms/arrays/__init__.py index 64ba13065..7e57f6376 100644 --- a/algorithms/arrays/__init__.py +++ b/algorithms/arrays/__init__.py @@ -11,4 +11,6 @@ from .rotate import * from .summarize_ranges import * from .three_sum import * +from .trimmean import * +from .top_1 import * from .two_sum import * diff --git a/algorithms/arrays/top_1.py b/algorithms/arrays/top_1.py new file mode 100644 index 000000000..dea9aa2f9 --- /dev/null +++ b/algorithms/arrays/top_1.py @@ -0,0 +1,32 @@ +""" +this algorithms receive array and check most_frequent_value(a.k.a mode). Also, sometimes it can be have numerous most_frequent_value, +so this funtion returns list. This result can be used as finding representative value on array. + +This algorithms get array, and make dictionary of it, find most frequent count, and make result list. + +For example) top_1([1, 1, 2, 2, 3, 4]) will return [1, 2] + +Complexity: O(n) +""" +def top_1(arr): + values = {} + #reserve each value which first appears on keys + #reserve how many time each value appears by index number on values + result = [] + f_val = 0 + + for i in arr: + if i in values: + values[i] += 1 + else: + values[i] = 1 + + f_val = max(values.values()) + + for i in values.keys(): + if values[i] == f_val: + result.append(i) + else: + continue + + return result diff --git a/algorithms/arrays/trimmean.py b/algorithms/arrays/trimmean.py new file mode 100644 index 000000000..4cea0db74 --- /dev/null +++ b/algorithms/arrays/trimmean.py @@ -0,0 +1,22 @@ +""" +When make reliable means, we need to neglect best and worst value. For example, when making average score on athletes we need this option. +So, this algorithms, fix some percentage to neglect when making mean. For example, if you suggest 20%, it will neglect best 10% value, and +worst 10% value. + +This algorithm gets array and percentage to neglect. After sorted, if index of array is larger or smaller or wanted ratio, we don't +compute it. + +Compleity: O(n) +""" +def trimmean(arr, per): + ratio = per/200 + # /100 for easy calculation by *, and /2 for easy adaption to best and worst parts. + cal_sum = 0 + # sum value to be calculated to trimmean. + arr.sort() + neg_val = int(len(arr)*ratio) + arr = arr[neg_val:len(arr)-neg_val] + for i in arr: + cal_sum += i + #print(cal_sum, len(arr)) + return cal_sum/len(arr) diff --git a/tests/test_array.py b/tests/test_array.py index ed398bca7..e3f6f6d7b 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -12,7 +12,9 @@ summarize_ranges, three_sum, two_sum, - max_ones_index + max_ones_index, + trimmean, + top_1 ) import unittest @@ -306,6 +308,20 @@ def test_two_sum(self): self.assertTupleEqual((0, 3), two_sum([-3, 5, 2, 3, 8, -9], target=0)) self.assertIsNone(two_sum([-3, 5, 2, 3, 8, -9], target=6)) + +class TestTrimmean(unittest.TestCase): + + def test_trimmean(self): + + self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 20), 5.5) + self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 20), 6.0) + +class TestTop1(unittest.TestCase): + + def test_top_1(self): + self.assertListEqual(top_1([1 , 1, 2, 2, 3]), [1, 2]) + self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), [23]) + if __name__ == '__main__': From 3d1956dc2fc6484701f5abaead8afa8092d4d805 Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Mon, 11 Jun 2018 02:37:21 +0900 Subject: [PATCH 069/302] Created check_bipartite.py in algorithms/graph + test cases (#347) * Update __init__.py * Update test_graph.py * Create check_bipartite.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update check_bipartite.py * Update check_bipartite.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/graph/__init__.py | 1 + algorithms/graph/check_bipartite.py | 39 +++++++++++++++++++++++++++++ tests/test_graph.py | 15 +++++++++++ 8 files changed, 60 insertions(+) create mode 100644 algorithms/graph/check_bipartite.py diff --git a/README.md b/README.md index 18858ce8e..0ccc81e6d 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ If you want to uninstall algorithms, it is as simple as: - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) - [graph](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - [clone_graph](algorithms/graph/clone_graph.py) - [cycle_detection](algorithms/graph/cycle_detection.py) diff --git a/README_CN.md b/README_CN.md index db759e9f0..7a791bbee 100644 --- a/README_CN.md +++ b/README_CN.md @@ -142,6 +142,7 @@ pip3 uninstall -y algorithms - [regex_matching:正则匹配](algorithms/dp/regex_matching.py) - [word_break:单词分割](algorithms/dp/word_break.py) - [graph:图](graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) - [2-sat:2-sat](algorithms/graph/satisfiability.py) - [clone_graph:克隆图](algorithms/graph/clone_graph.py) - [cycle_detection:判断圈算法](algorithms/graph/cycle_detection.py) diff --git a/README_GE.md b/README_GE.md index f0a48ca9b..1f6c5b32a 100644 --- a/README_GE.md +++ b/README_GE.md @@ -146,6 +146,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) - [graph](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - [clone_graph](algorithms/graph/clone_graph.py) - [cycle_detection](algorithms/graph/cycle_detection.py) diff --git a/README_JP.md b/README_JP.md index d50f01253..1e0a2d2b0 100644 --- a/README_JP.md +++ b/README_JP.md @@ -140,6 +140,7 @@ if __name__ == "__main__": - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) - [graph : グラフ](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - [clone_graph](algorithms/graph/clone_graph.py) - [cycle_detection](algorithms/graph/cycle_detection.py) diff --git a/README_KR.md b/README_KR.md index dd78fa0d9..ff96562c0 100644 --- a/README_KR.md +++ b/README_KR.md @@ -137,6 +137,7 @@ if __name__ == "__main__": - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) - [graph : 그래프](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - [clone_graph](algorithms/graph/clone_graph.py) - [cycle_detection](algorithms/graph/cycle_detection.py) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index bfb208eb0..f94f12c5c 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -1 +1,2 @@ from .tarjan import * +from .check_bipartite import * diff --git a/algorithms/graph/check_bipartite.py b/algorithms/graph/check_bipartite.py new file mode 100644 index 000000000..dacc003b3 --- /dev/null +++ b/algorithms/graph/check_bipartite.py @@ -0,0 +1,39 @@ +""" + +Bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets. +(https://en.wikipedia.org/wiki/Bipartite_graph) + +Time complexity is O(|E|) +Space complexity is O(|V|) + +""" + +def check_bipartite(adj_list): + + V = len(adj_list) + + # Divide vertexes in the graph into set_type 1 and 2 + # Initialize all set_types as -1 + set_type = [-1 for v in range(V)] + set_type[0] = 0 + + q = [0] + + while q: + v = q.pop(0) + + # If there is a self-loop, it cannot be bipartite + if adj_list[v][v]: + return False + + for u in range(V): + if adj_list[v][u]: + if set_type[u] == set_type[v]: + return False + elif set_type[u] == -1: + # set type of u opposite of v + set_type[u] = 1 - set_type[v] + q.append(u) + + return True + diff --git a/tests/test_graph.py b/tests/test_graph.py index 63937db0e..d402b86fa 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,4 +1,5 @@ from algorithms.graph import Tarjan +from algorithms.graph import check_bipartite import unittest @@ -42,3 +43,17 @@ def test_tarjan_example_2(self): g = Tarjan(example) self.assertEqual(g.sccs, [['A', 'B', 'E'], ['C', 'D'], ['F', 'G'], ['H']]) + + +class TestCheckBipartite(unittest.TestCase): + + def test_check_bipartite(self): + + adj_list_1 = [[0, 0, 1], [0, 0, 1], [1, 1, 0]] + self.assertEqual(True, check_bipartite(adj_list_1)) + + adj_list_2 = [[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 1, 0]] + self.assertEqual(True, check_bipartite(adj_list_2)) + + adj_list_3 = [[0, 1, 0, 0], [1, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 0]] + self.assertEqual(False, check_bipartite(adj_list_3)) From 1ac287f4a84cc75950955f2b512c75884669083a Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Sun, 10 Jun 2018 23:25:31 +0530 Subject: [PATCH 070/302] refactor PriorityQueue and tests (#348) --- algorithms/queues/priority_queue.py | 73 ++++++++++++++++++----------- tests/test_queues.py | 37 +++++++-------- 2 files changed, 63 insertions(+), 47 deletions(-) diff --git a/algorithms/queues/priority_queue.py b/algorithms/queues/priority_queue.py index a28ae9697..76b08156e 100644 --- a/algorithms/queues/priority_queue.py +++ b/algorithms/queues/priority_queue.py @@ -3,37 +3,54 @@ Insertion - O(n) Extract min/max Node - O(1) """ -import collections +import itertools class PriorityQueueNode: - def __init__(self, data, priority): - self.data = data - self.priority = priority + def __init__(self, data, priority): + self.data = data + self.priority = priority + + def __repr__(self): + return "{}: {}".format(self.data, self.priority) - def __repr__(self): - return str(self.data) + ": " + str(self.priority) class PriorityQueue: - def __init__(self): - self.priority_queue_list = collections.deque() - - def __repr__(self): - return "PriorityQueue({!r})".format(list(self.priority_queue_list)) - - def size(self): - return len(self.priority_queue_list) - - def push(self, item, priority=None): - priority = item if priority is None else priority - node = PriorityQueueNode(item, priority) - for index, current in enumerate(self.priority_queue_list): - if current.priority > node.priority: - self.priority_queue_list.insert(index, node) - return - # when traversed complete queue - self.priority_queue_list.append(node) - - def pop(self): - # remove and return the first node from the queue - return self.priority_queue_list.popleft() + def __init__(self, items=None, priorities=None): + """Create a priority queue with items (list or iterable). + If items is not passed, create empty priority queue.""" + self.priority_queue_list = [] + if items is None: + return + if priorities is None: + priorities = itertools.repeat(None) + for item, priority in zip(items, priorities): + self.push(item, priority=priority) + + def __repr__(self): + return "PriorityQueue({!r})".format(self.priority_queue_list) + + def size(self): + """Return size of the priority queue. + """ + return len(self.priority_queue_list) + + def push(self, item, priority=None): + """Push the item in the priority queue. + if priority is not given, priority is set to the value of item. + """ + priority = item if priority is None else priority + node = PriorityQueueNode(item, priority) + for index, current in enumerate(self.priority_queue_list): + if current.priority < node.priority: + self.priority_queue_list.insert(index, node) + return + # when traversed complete queue + self.priority_queue_list.append(node) + + def pop(self): + """Remove and return the item with the lowest priority. + """ + # remove and return the first node from the queue + return self.priority_queue_list.pop().data + diff --git a/tests/test_queues.py b/tests/test_queues.py index 2c85c4508..b5b49ef61 100644 --- a/tests/test_queues.py +++ b/tests/test_queues.py @@ -1,11 +1,12 @@ +import unittest + from algorithms.queues import ( ArrayQueue, LinkedListQueue, max_sliding_window, reconstruct_queue, - PriorityQueue, PriorityQueueNode + PriorityQueue ) -import unittest class TestQueue(unittest.TestCase): """ @@ -70,10 +71,9 @@ def test_LinkedListQueue(self): self.assertTrue(queue.is_empty()) -class TestSuite(unittest.TestCase): +class TestSuite(unittest.TestCase): def test_max_sliding_window(self): - array = [1, 3, -1, -3, 5, 3, 6, 7] self.assertEqual(max_sliding_window(array, k=5), [5, 5, 6, 7]) self.assertEqual(max_sliding_window(array, k=3), [3, 3, 5, 5, 6, 7]) @@ -85,24 +85,23 @@ def test_max_sliding_window(self): self.assertEqual(max_sliding_window(array, k=2), [8, 10, 10, 9, 9, 15, 15, 90, 90]) def test_reconstruct_queue(self): - self.assertEqual([[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]], - reconstruct_queue([[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]])) + self.assertEqual([[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]], + reconstruct_queue([[7, 0], [4, 4], [7, 1], [5, 0], [6, 1], [5, 2]])) -""" - TODO: Refactor PriorityQueue because insert method does not work for python3.4 -class TestPriorityQueue(unittest.TestCase): - Test suite for the PriorityQueue data structures. +class TestPriorityQueue(unittest.TestCase): + """Test suite for the PriorityQueue data structures. + """ def test_PriorityQueue(self): - queue = PriorityQueue() - queue.push(3) - queue.push(4) - queue.push(1) - queue.push(6) - self.assertEqual(4,queue.size()) - self.assertEqual(str(1) + ": " + str(1),str(queue.pop())) -""" -if __name__ == "__main__": + queue = PriorityQueue([3, 4, 1, 6]) + self.assertEqual(4, queue.size()) + self.assertEqual(1, queue.pop()) + self.assertEqual(3, queue.size()) + queue.push(2) + self.assertEqual(4, queue.size()) + self.assertEqual(2, queue.pop()) + +if __name__ == "__main__": unittest.main() From d4ec1edc38338bf101708e453e1ae657e2d1a02a Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Sun, 10 Jun 2018 13:45:46 -0700 Subject: [PATCH 071/302] added some path problems in new algorithms/unix/ (#344) * Add join_with_slash.py to Unix * Add full_path.py to Unix * Add split.py to Unix --- README.md | 5 ++++ algorithms/unix/__init__.py | 3 +++ algorithms/unix/path/full_path.py | 6 +++++ algorithms/unix/path/join_with_slash.py | 18 +++++++++++++ algorithms/unix/path/split.py | 23 ++++++++++++++++ tests/test_unix.py | 35 +++++++++++++++++++++++++ 6 files changed, 90 insertions(+) create mode 100644 algorithms/unix/__init__.py create mode 100644 algorithms/unix/path/full_path.py create mode 100644 algorithms/unix/path/join_with_slash.py create mode 100644 algorithms/unix/path/split.py create mode 100644 tests/test_unix.py diff --git a/README.md b/README.md index 0ccc81e6d..599378ebf 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,11 @@ If you want to uninstall algorithms, it is as simple as: - [pretty_print](algorithms/tree/pretty_print.py) - [same_tree](algorithms/tree/same_tree.py) - [tree](algorithms/tree/tree.py) +- [unix](algorithms/unix) + - [path](algorithms/unix/path/) + - [join_with_slash](algorithms/unix/path/join_with_slash.py) + - [full_path](algorithms/unix/path/full_path.py) + - [split](algorithms/unix/path/split.py) - [union-find](algorithms/union-find) - [count_islands](algorithms/union-find/count_islands.py) diff --git a/algorithms/unix/__init__.py b/algorithms/unix/__init__.py new file mode 100644 index 000000000..68b785c97 --- /dev/null +++ b/algorithms/unix/__init__.py @@ -0,0 +1,3 @@ +from .path.join_with_slash import * +from .path.full_path import * +from .path.split import * diff --git a/algorithms/unix/path/full_path.py b/algorithms/unix/path/full_path.py new file mode 100644 index 000000000..3bf109e12 --- /dev/null +++ b/algorithms/unix/path/full_path.py @@ -0,0 +1,6 @@ +""" +Get a full absolute path a file +""" +import os +def full_path(file): + return os.path.abspath(os.path.expanduser(file)) diff --git a/algorithms/unix/path/join_with_slash.py b/algorithms/unix/path/join_with_slash.py new file mode 100644 index 000000000..beec8d106 --- /dev/null +++ b/algorithms/unix/path/join_with_slash.py @@ -0,0 +1,18 @@ +""" +Both URL and file path joins use slashes as dividers between their parts. +For example: + +path/to/dir + file --> path/to/dir/file +path/to/dir/ + file --> path/to/dir/file +http://algorithms.com/ + part --> http://algorithms.com/part +http://algorithms.com + part --> http://algorithms/part +""" +import os + +def join_with_slash(base, suffix): + # Remove / trailing + base = base.rstrip('/') + # Remove / leading + suffix = suffix.lstrip('/').rstrip() + full_path = "{}/{}".format(base, suffix) + return full_path diff --git a/algorithms/unix/path/split.py b/algorithms/unix/path/split.py new file mode 100644 index 000000000..168b12057 --- /dev/null +++ b/algorithms/unix/path/split.py @@ -0,0 +1,23 @@ +""" +Splitting a path into 2 parts +Example: +Input: https://algorithms/unix/test.py (for url) +Output: + part[0]: https://algorithms/unix + part[1]: test.py + +Input: algorithms/unix/test.py (for file path) +Output: + part[0]: algorithms/unix + part[1]: test.py +""" +import os + +def split(path): + parts = [] + split_part = path.rpartition('/') + # Takt the origin path without the last part + parts.append(split_part[0]) + # Take the last element of list + parts.append(split_part[2]) + return parts diff --git a/tests/test_unix.py b/tests/test_unix.py new file mode 100644 index 000000000..a24388970 --- /dev/null +++ b/tests/test_unix.py @@ -0,0 +1,35 @@ +from algorithms.unix import ( + join_with_slash, + full_path, + split +) +import os +import unittest +class TestUnixPath(unittest.TestCase): + def test_join_with_slash(self): + self.assertEqual("path/to/dir/file", join_with_slash("path/to/dir/", "file")) + self.assertEqual("path/to/dir/file", join_with_slash("path/to/dir", "file")) + self.assertEqual("http://algorithms/part", join_with_slash("http://algorithms", "part")) + self.assertEqual("http://algorithms/part", join_with_slash("http://algorithms/", "part")) + + def test_full_path(self): + file_name = "file_name" + # Test full path relative + expect_path = "{}/{}".format(os.getcwd(), file_name) + self.assertEqual(expect_path, full_path(file_name)) + # Test full path with expanding user + # ~/file_name + expect_path = "{}/{}".format(os.path.expanduser('~'), file_name) + self.assertEqual(expect_path, full_path("~/{}".format(file_name))) + + def test_split(self): + # Test url path + path = "https://algorithms/unix/test.py" + expect_result = split(path) + self.assertEqual("https://algorithms/unix", expect_result[0]) + self.assertEqual("test.py", expect_result[1]) + # Test file path + path = "algorithms/unix/test.py" + expect_result = split(path) + self.assertEqual("algorithms/unix", expect_result[0]) + self.assertEqual("test.py", expect_result[1]) From 7a21ac55c064dccbb6dfdb29cea4c36c05cbfa1c Mon Sep 17 00:00:00 2001 From: Lee Geon Date: Mon, 11 Jun 2018 05:47:38 +0900 Subject: [PATCH 072/302] Created Preorder & Postorder traversals in tree (#346) * Create postorder.py * Create preorder.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update inorder.py * Update postorder.py * Update preorder.py * Create __init__.py * Update preorder.py * Update postorder.py * Create test_tree.py * Update test_tree.py * Update __init__.py * Update __init__.py * Update test_tree.py --- README.md | 2 ++ README_CN.md | 2 ++ README_GE.md | 2 ++ README_JP.md | 2 ++ README_KR.md | 2 ++ algorithms/tree/traversal/__init__.py | 2 ++ algorithms/tree/traversal/inorder.py | 4 +++ algorithms/tree/traversal/postorder.py | 41 +++++++++++++++++++++++ algorithms/tree/traversal/preorder.py | 38 +++++++++++++++++++++ tests/test_tree.py | 46 ++++++++++++++++++++++++++ 10 files changed, 141 insertions(+) create mode 100644 algorithms/tree/traversal/__init__.py create mode 100644 algorithms/tree/traversal/postorder.py create mode 100644 algorithms/tree/traversal/preorder.py create mode 100644 tests/test_tree.py diff --git a/README.md b/README.md index 599378ebf..d85ec4429 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,8 @@ If you want to uninstall algorithms, it is as simple as: - [traversal](algorithms/tree/traversal) - [inorder](algorithms/tree/traversal/inorder.py) - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) - [zigzag](algorithms/tree/traversal/zigzag.py) - [trie](algorithms/tree/trie) - [add_and_search](algorithms/tree/trie/add_and_search.py) diff --git a/README_CN.md b/README_CN.md index 7a791bbee..b675f6f6a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -291,6 +291,8 @@ pip3 uninstall -y algorithms - [traversal:遍历](algorithms/tree/traversal) - [inorder:中序遍历](algorithms/tree/traversal/inorder.py) - [level_order:层次遍历](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) - [zigzag:锯齿形遍历](algorithms/tree/traversal/zigzag.py) - [tree:树](algorithms/tree/tree.py) - [trie:字典树](algorithms/tree/trie) diff --git a/README_GE.md b/README_GE.md index 1f6c5b32a..e21dca321 100644 --- a/README_GE.md +++ b/README_GE.md @@ -313,6 +313,8 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [traversal](algorithms/tree/traversal) - [inorder](algorithms/tree/traversal/inorder.py) - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) - [zigzag](algorithms/tree/traversal/zigzag.py) - [trie](algorithms/tree/trie) - [add_and_search](algorithms/tree/trie/add_and_search.py) diff --git a/README_JP.md b/README_JP.md index 1e0a2d2b0..636d79f60 100644 --- a/README_JP.md +++ b/README_JP.md @@ -307,6 +307,8 @@ if __name__ == "__main__": - [traversal](algorithms/tree/traversal) - [inorder](algorithms/tree/traversal/inorder.py) - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) - [zigzag](algorithms/tree/traversal/zigzag.py) - [trie](algorithms/tree/trie) - [add_and_search](algorithms/tree/trie/add_and_search.py) diff --git a/README_KR.md b/README_KR.md index ff96562c0..b38cdd4cb 100644 --- a/README_KR.md +++ b/README_KR.md @@ -302,6 +302,8 @@ if __name__ == "__main__": - [traversal : 트리 순회](algorithms/tree/traversal) - [inorder](algorithms/tree/traversal/inorder.py) - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) - [zigzag](algorithms/tree/traversal/zigzag.py) - [trie : 트라이](algorithms/tree/trie) - [add_and_search](algorithms/tree/trie/add_and_search.py) diff --git a/algorithms/tree/traversal/__init__.py b/algorithms/tree/traversal/__init__.py new file mode 100644 index 000000000..df3c88c05 --- /dev/null +++ b/algorithms/tree/traversal/__init__.py @@ -0,0 +1,2 @@ +from .preorder import * +from .postorder import * diff --git a/algorithms/tree/traversal/inorder.py b/algorithms/tree/traversal/inorder.py index 4883c0f4f..17cadaf95 100644 --- a/algorithms/tree/traversal/inorder.py +++ b/algorithms/tree/traversal/inorder.py @@ -1,3 +1,7 @@ +''' +Time complexity : O(n) +''' + class Node: def __init__(self, val, left=None, right=None): diff --git a/algorithms/tree/traversal/postorder.py b/algorithms/tree/traversal/postorder.py new file mode 100644 index 000000000..b89293bba --- /dev/null +++ b/algorithms/tree/traversal/postorder.py @@ -0,0 +1,41 @@ +''' +Time complexity : O(n) +''' + +class Node: + + def __init__(self, val, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +def postorder(root): + res_temp = [] + res = [] + if not root: + return res + stack = [] + stack.append(root) + while stack: + root = stack.pop() + res_temp.append(root.val) + if root.left: + stack.append(root.left) + if root.right: + stack.append(root.right) + while res_temp: + res.append(res_temp.pop()) + return res + +# Recursive Implementation +def postorder_rec(root, res=None): + if root is None: + return [] + if res is None: + res = [] + postorder_rec(root.left, res) + postorder_rec(root.right, res) + res.append(root.val) + return res + diff --git a/algorithms/tree/traversal/preorder.py b/algorithms/tree/traversal/preorder.py new file mode 100644 index 000000000..45346ba87 --- /dev/null +++ b/algorithms/tree/traversal/preorder.py @@ -0,0 +1,38 @@ +''' +Time complexity : O(n) +''' + +class Node: + + def __init__(self, val, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +def preorder(root): + res = [] + if not root: + return res + stack = [] + stack.append(root) + while stack: + root = stack.pop() + res.append(root.val) + if root.right: + stack.append(root.right) + if root.left: + stack.append(root.left) + return res + +# Recursive Implementation +def preorder_rec(root, res=None): + if root is None: + return [] + if res is None: + res = [] + res.append(root.val) + preorder_rec(root.left, res) + preorder_rec(root.right, res) + return res + diff --git a/tests/test_tree.py b/tests/test_tree.py new file mode 100644 index 000000000..a9d53ca6d --- /dev/null +++ b/tests/test_tree.py @@ -0,0 +1,46 @@ +from algorithms.tree.traversal import ( + preorder, + preorder_rec, + postorder, + postorder_rec +) + +import unittest + +class Node: + + def __init__(self, val, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class TestTraversal(unittest.TestCase): + + def test_preorder(self): + n1 = Node(100) + n2 = Node(50) + n3 = Node(150) + n4 = Node(25) + n5 = Node(75) + n6 = Node(125) + n7 = Node(175) + n1.left, n1.right = n2, n3 + n2.left, n2.right = n4, n5 + n3.left, n3.right = n6, n7 + self.assertEqual([100, 50, 25, 75, 150, 125, 175], preorder(n1)) + self.assertEqual([100, 50, 25, 75, 150, 125, 175], preorder_rec(n1)) + + def test_postorder(self): + n1 = Node(100) + n2 = Node(50) + n3 = Node(150) + n4 = Node(25) + n5 = Node(75) + n6 = Node(125) + n7 = Node(175) + n1.left, n1.right = n2, n3 + n2.left, n2.right = n4, n5 + n3.left, n3.right = n6, n7 + self.assertEqual([25, 75, 50, 125, 175, 150, 100], postorder(n1)) + self.assertEqual([25, 75, 50, 125, 175, 150, 100], postorder_rec(n1)) From 89c1daaf04ff893ddad7e3d936c2ab3456abdbc6 Mon Sep 17 00:00:00 2001 From: hsi1032 Date: Mon, 11 Jun 2018 05:49:33 +0900 Subject: [PATCH 073/302] added simulation code in quick_sort and heap_sort (#342) * Update quick_sort.py * Update heap_sort.py * Update heap_sort.py * Update quick_sort.py * Update heap_sort.py * Update quick_sort.py --- algorithms/sort/heap_sort.py | 39 +++++++++++++++++++++++++---------- algorithms/sort/quick_sort.py | 22 +++++++++++++------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/algorithms/sort/heap_sort.py b/algorithms/sort/heap_sort.py index 6c91cee90..ec4c7fa2b 100644 --- a/algorithms/sort/heap_sort.py +++ b/algorithms/sort/heap_sort.py @@ -1,17 +1,21 @@ -def max_heap_sort(arr): +def max_heap_sort(arr, simulation=False): """ Heap Sort that uses a max heap to sort an array in ascending order Complexity: O(n log(n)) """ + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + for i in range(len(arr) - 1, 0, -1): - max_heapify(arr, i) + iteration = max_heapify(arr, i, simulation, iteration) - temp = arr[0] - arr[0] = arr[i] - arr[i] = temp + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) return arr -def max_heapify(arr, end): +def max_heapify(arr, end, simulation, iteration): """ Max heapify helper for max_heap_sort """ last_parent = (end - 1) // 2 @@ -31,21 +35,30 @@ def max_heapify(arr, end): if arr[child] > arr[current_parent]: arr[current_parent], arr[child] = arr[child], arr[current_parent] current_parent = child + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) # If no swap occured, no need to keep iterating else: break + arr[0], arr[end] = arr[end], arr[0] + return iteration - -def min_heap_sort(arr): +def min_heap_sort(arr, simulation=False): """ Heap Sort that uses a min heap to sort an array in ascending order Complexity: O(n log(n)) """ + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + for i in range(0, len(arr) - 1): - min_heapify(arr, i) + iteration = min_heapify(arr, i, simulation, iteration) + return arr -def min_heapify(arr, start): +def min_heapify(arr, start, simulation, iteration): """ Min heapify helper for min_heap_sort """ # Offset last_parent by the start (last_parent calculated as if start index was 0) @@ -64,12 +77,16 @@ def min_heapify(arr, start): if child + 1 <= end - start and arr[child + start] > arr[ child + 1 + start]: child = child + 1 - + # Swap if child is less than parent if arr[child + start] < arr[current_parent + start]: arr[current_parent + start], arr[child + start] = \ arr[child + start], arr[current_parent + start] current_parent = child + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) # If no swap occured, no need to keep iterating else: break + return iteration diff --git a/algorithms/sort/quick_sort.py b/algorithms/sort/quick_sort.py index a262bb4c1..10794e7a5 100644 --- a/algorithms/sort/quick_sort.py +++ b/algorithms/sort/quick_sort.py @@ -1,18 +1,26 @@ -def quick_sort(arr): +def quick_sort(arr, simulation=False): """ Quick sort Complexity: best O(n log(n)) avg O(n log(n)), worst O(N^2) """ - return quick_sort_recur(arr, 0, len(arr) - 1) - + + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + arr, _ = quick_sort_recur(arr, 0, len(arr) - 1, iteration, simulation) + return arr -def quick_sort_recur(arr, first, last): +def quick_sort_recur(arr, first, last, iteration, simulation): if first < last: pos = partition(arr, first, last) # Start our two recursive calls - quick_sort_recur(arr, first, pos - 1) - quick_sort_recur(arr, pos + 1, last) - return arr + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) + + _, iteration = quick_sort_recur(arr, first, pos - 1, iteration, simulation) + _, iteration = quick_sort_recur(arr, pos + 1, last, iteration, simulation) + return arr, iteration def partition(arr, first, last): wall = first From 5fd35cad82ca009395aef07a38d2afc483353845 Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Tue, 12 Jun 2018 19:51:34 +0530 Subject: [PATCH 074/302] remove `tests/*` from MANIFEST.in (#354) - fix #350 --- MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index daf8a5200..50af9b9c9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,3 @@ include README.md include LICENSE include algorithms/* -include tests/* From 2f361dd92e83768df85a14e3147e6aa6f770150e Mon Sep 17 00:00:00 2001 From: aig031 <31883686+aig031@users.noreply.github.com> Date: Thu, 14 Jun 2018 04:33:01 +0900 Subject: [PATCH 075/302] created limit.py in /algorithms/arrays (#353) * Create top_1.py * Create trimmean.py * Rename top_1.py to algorithms/arrays/top_1.py * Rename trimmean.py to algorithms/arrays/trimmean.py * Update __init__.py * Update README.md * Update README_CN.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_array.py * Update test_array.py * Update test_array.py * Create limit.py * Update __init__.py * Update test_array.py * Update README.md * Update README_CN.md * Update README_GE.md * Update README_JP.md * Update README_KR.md * Update test_array.py * Update limit.py * Update test_array.py --- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/arrays/__init__.py | 1 + algorithms/arrays/limit.py | 30 ++++++++++++++++++++++++++++++ tests/test_array.py | 11 ++++++++++- 8 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 algorithms/arrays/limit.py diff --git a/README.md b/README.md index d85ec4429..c03beceda 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ If you want to uninstall algorithms, it is as simple as: - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) diff --git a/README_CN.md b/README_CN.md index b675f6f6a..42f7b36d0 100644 --- a/README_CN.md +++ b/README_CN.md @@ -78,6 +78,7 @@ pip3 uninstall -y algorithms - [garage:停车场](algorithms/arrays/garage.py) - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus.py) - [max_ones_index](algorithms/arrays/max_ones_index.py) + - [limit](algorithms/arrays/limit.py) - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) diff --git a/README_GE.md b/README_GE.md index e21dca321..f9f475709 100644 --- a/README_GE.md +++ b/README_GE.md @@ -67,6 +67,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) diff --git a/README_JP.md b/README_JP.md index 636d79f60..571c70fe7 100644 --- a/README_JP.md +++ b/README_JP.md @@ -61,6 +61,7 @@ if __name__ == "__main__": - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) diff --git a/README_KR.md b/README_KR.md index b38cdd4cb..773babd94 100644 --- a/README_KR.md +++ b/README_KR.md @@ -60,6 +60,7 @@ if __name__ == "__main__": - [flatten](algorithms/arrays/flatten.py) - [garage](algorithms/arrays/garage.py) - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [merge_intervals](algorithms/arrays/merge_intervals.py) diff --git a/algorithms/arrays/__init__.py b/algorithms/arrays/__init__.py index 7e57f6376..c0d8b8f23 100644 --- a/algorithms/arrays/__init__.py +++ b/algorithms/arrays/__init__.py @@ -14,3 +14,4 @@ from .trimmean import * from .top_1 import * from .two_sum import * +from .limit import * diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py new file mode 100644 index 000000000..adcc57797 --- /dev/null +++ b/algorithms/arrays/limit.py @@ -0,0 +1,30 @@ +""" +Sometimes you need to limit array result to use. Such as you only need the value over +10 or, you need value under than 100. By use this algorithms, you can limit your array +to specific value + +If array, Min, Max value was given, it returns array that contains values of given array +which was larger than Min, and lower than Max. You need to give 'unlimit' to use only Min +or Max. + +ex) limit([1,2,3,4,5], None, 3) = [1,2,3] + +Complexity = O(n) +""" + +def limit(arr, min_lim = None, max_lim = None): + result = [] + if min_lim == None: + for i in arr: + if i<= max_lim: + result.append(i) + elif max_lim == None: + for i in arr: + if i >= min_lim: + result.append(i) + else: + for i in arr: + if i >= min_lim and i <= max_lim: + result.append(i) + + return result diff --git a/tests/test_array.py b/tests/test_array.py index e3f6f6d7b..6002adb43 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -14,7 +14,8 @@ two_sum, max_ones_index, trimmean, - top_1 + top_1, + limit ) import unittest @@ -322,6 +323,14 @@ def test_top_1(self): self.assertListEqual(top_1([1 , 1, 2, 2, 3]), [1, 2]) self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), [23]) +class TestLimit(unittest.TestCase): + + def test_limit(self): + self.assertListEqual(limit([1, 2, 3, 4, 5], 2, 4), [2, 3, 4]) + self.assertListEqual(limit([1, 2, 3, 4, 5], 2), [2, 3, 4, 5]) + self.assertListEqual(limit([1, 2, 3, 4, 5], None, 4), [1, 2, 3, 4]) + + if __name__ == '__main__': From 27d53fbb4cba6cc79c62daf86f70cb23c7686e32 Mon Sep 17 00:00:00 2001 From: NormalB Date: Thu, 14 Jun 2018 04:36:13 +0900 Subject: [PATCH 076/302] added radix sort for simulation (#351) --- algorithms/sort/radix_sort.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/algorithms/sort/radix_sort.py b/algorithms/sort/radix_sort.py index fee0f2f7f..dd4113d05 100644 --- a/algorithms/sort/radix_sort.py +++ b/algorithms/sort/radix_sort.py @@ -2,10 +2,14 @@ radix sort complexity: O(nk) . n is the size of input list and k is the digit length of the number """ -def radix_sort(arr): +def radix_sort(arr, simulation=False): is_done = False position = 1 + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + while not is_done: queue_list = [list() for _ in range(10)] is_done = True @@ -22,5 +26,9 @@ def radix_sort(arr): arr[index] = num index += 1 + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) + position *= 10 return arr From 18b9ce123042bec808b7f2736fa8f4549afe2493 Mon Sep 17 00:00:00 2001 From: ppuzzle Date: Thu, 14 Jun 2018 12:51:29 +0900 Subject: [PATCH 077/302] added simulation to bogo_sort.py (#355) --- algorithms/sort/bogo_sort.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/algorithms/sort/bogo_sort.py b/algorithms/sort/bogo_sort.py index 074a6afca..60e1be8f0 100644 --- a/algorithms/sort/bogo_sort.py +++ b/algorithms/sort/bogo_sort.py @@ -1,11 +1,16 @@ import random -def bogo_sort(arr): +def bogo_sort(arr, simulation=False): """Bogo Sort Best Case Complexity: O(n) Worst Case Complexity: O(∞) Average Case Complexity: O(n(n-1)!) """ + + iteration = 0 + if simulation: + print("iteration",iteration,":",*arr) + def is_sorted(arr): #check the array is inorder i = 0 @@ -14,9 +19,14 @@ def is_sorted(arr): if arr[i] > arr[i+1]: return False i += 1 + + return True while not is_sorted(arr): random.shuffle(arr) + + if simulation: + iteration = iteration + 1 + print("iteration",iteration,":",*arr) + return arr - - From 7cbe6e1b6712d139b8859489405fc95be822c829 Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Sat, 16 Jun 2018 04:54:16 -0700 Subject: [PATCH 078/302] Added some String algorithm (#356) * Add unique morse * Add judge_circle * Add strong password --- README.md | 3 + algorithms/strings/__init__.py | 3 + algorithms/strings/judge_circle.py | 25 +++++++ algorithms/strings/strong_password.py | 43 ++++++++++++ algorithms/strings/unique_morse.py | 94 +++++++++++++++++++++++++++ tests/test_strings.py | 23 ++++++- 6 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 algorithms/strings/judge_circle.py create mode 100644 algorithms/strings/strong_password.py create mode 100644 algorithms/strings/unique_morse.py diff --git a/README.md b/README.md index c03beceda..73877e476 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,9 @@ If you want to uninstall algorithms, it is as simple as: - [reverse_words](algorithms/strings/reverse_words.py) - [roman_to_int](algorithms/strings/roman_to_int.py) - [word_squares](algorithms/strings/word_squares.py) + - [unique_morse](algorithms/strings/unique_morse.py) + - [judge_circle](algorithms/strings/judge_circle.py) + - [strong_password](algorithms/strings/strong_password.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index b4d1bb4c0..a74dbf06d 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -21,3 +21,6 @@ from .strip_url_params import * from .validate_coordinates import * from .word_squares import * +from .unique_morse import * +from .judge_circle import * +from .strong_password import * diff --git a/algorithms/strings/judge_circle.py b/algorithms/strings/judge_circle.py new file mode 100644 index 000000000..46468a1ad --- /dev/null +++ b/algorithms/strings/judge_circle.py @@ -0,0 +1,25 @@ +""" +Initially, there is a Robot at position (0, 0). Given a sequence of its moves, +judge if this robot makes a circle, which means it moves back to the original place. + +The move sequence is represented by a string. And each move is represent by a +character. The valid robot moves are R (Right), L (Left), U (Up) and D (down). +The output should be true or false representing whether the robot makes a circle. + +Example 1: +Input: "UD" +Output: true +Example 2: +Input: "LL" +Output: false +""" +def judge_circle(moves): + dict_moves = { + 'U' : 0, + 'D' : 0, + 'R' : 0, + 'L' : 0 + } + for char in moves: + dict_moves[char] = dict_moves[char] + 1 + return dict_moves['L'] == dict_moves['R'] and dict_moves['U'] == dict_moves['D'] diff --git a/algorithms/strings/strong_password.py b/algorithms/strings/strong_password.py new file mode 100644 index 000000000..85acd0223 --- /dev/null +++ b/algorithms/strings/strong_password.py @@ -0,0 +1,43 @@ +""" +The signup page required her to input a name and a password. However, the password +must be strong. The website considers a password to be strong if it satisfies the following criteria: + +1) Its length is at least 6. +2) It contains at least one digit. +3) It contains at least one lowercase English character. +4) It contains at least one uppercase English character. +5) It contains at least one special character. The special characters are: !@#$%^&*()-+ +She typed a random string of length in the password field but wasn't sure if it was strong. +Given the string she typed, can you find the minimum number of characters she must add to make her password strong? + +Note: Here's the set of types of characters in a form you can paste in your solution: +numbers = "0123456789" +lower_case = "abcdefghijklmnopqrstuvwxyz" +upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +special_characters = "!@#$%^&*()-+" + +Input Format +The first line contains an integer denoting the length of the string. +The second line contains a string consisting of characters, the password +typed by Louise. Each character is either a lowercase/uppercase English alphabet, a digit, or a special character. + +Sample Input 1: strong_password(3,"Ab1") +Output: 3 (Because She can make the password strong by adding characters,for example, $hk, turning the password into Ab1$hk which is strong. +2 characters aren't enough since the length must be at least 6.) + +Sample Output 2: strong_password(11,"#Algorithms") +Output: 1 (Because the password isn't strong, but she can make it strong by adding a single digit.) + +""" +def strong_password(n, password): + count_error = 0 + # Return the minimum number of characters to make the password strong + if any(i.isdigit() for i in password) == False: + count_error = count_error + 1 + if any(i.islower() for i in password) == False: + count_error = count_error + 1 + if any(i.isupper() for i in password) == False: + count_error = count_error + 1 + if any(i in '!@#$%^&*()-+' for i in password) == False: + count_error = count_error + 1 + return max(count_error, 6 - n) diff --git a/algorithms/strings/unique_morse.py b/algorithms/strings/unique_morse.py new file mode 100644 index 000000000..6d8618644 --- /dev/null +++ b/algorithms/strings/unique_morse.py @@ -0,0 +1,94 @@ +""" +International Morse Code defines a standard encoding where each letter is mapped to +a series of dots and dashes, as follows: "a" maps to ".-", "b" maps to "-...", "c" +maps to "-.-.", and so on. + +For convenience, the full table for the 26 letters of the English alphabet is given below: + 'a':".-", + 'b':"-...", + 'c':"-.-.", + 'd': "-..", + 'e':".", + 'f':"..-.", + 'g':"--.", + 'h':"....", + 'i':"..", + 'j':".---", + 'k':"-.-", + 'l':".-..", + 'm':"--", + 'n':"-.", + 'o':"---", + 'p':".--.", + 'q':"--.-", + 'r':".-.", + 's':"...", + 't':"-", + 'u':"..-", + 'v':"...-", + 'w':".--", + 'x':"-..-", + 'y':"-.--", + 'z':"--.." + +Now, given a list of words, each word can be written as a concatenation of the +Morse code of each letter. For example, "cab" can be written as "-.-.-....-", +(which is the concatenation "-.-." + "-..." + ".-"). We'll call such a +concatenation, the transformation of a word. + +Return the number of different transformations among all words we have. +Example: +Input: words = ["gin", "zen", "gig", "msg"] +Output: 2 +Explanation: +The transformation of each word is: +"gin" -> "--...-." +"zen" -> "--...-." +"gig" -> "--...--." +"msg" -> "--...--." + +There are 2 different transformations, "--...-." and "--...--.". +""" + +morse_code = { + 'a':".-", + 'b':"-...", + 'c':"-.-.", + 'd': "-..", + 'e':".", + 'f':"..-.", + 'g':"--.", + 'h':"....", + 'i':"..", + 'j':".---", + 'k':"-.-", + 'l':".-..", + 'm':"--", + 'n':"-.", + 'o':"---", + 'p':".--.", + 'q':"--.-", + 'r':".-.", + 's':"...", + 't':"-", + 'u':"..-", + 'v':"...-", + 'w':".--", + 'x':"-..-", + 'y':"-.--", + 'z':"--.." +} +def convert_morse_word(word): + morse_word = "" + word = word.lower() + for char in word: + morse_word = morse_word + morse_code[char] + return morse_word + +def unique_morse(words): + unique_morse_word = [] + for word in words: + morse_word = convert_morse_word(word) + if morse_word not in unique_morse_word: + unique_morse_word.append(morse_word) + return len(unique_morse_word) diff --git a/tests/test_strings.py b/tests/test_strings.py index 31e0d3ed5..0cda82cc5 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -23,7 +23,10 @@ strip_url_params1, strip_url_params2, strip_url_params3, is_valid_coordinates_0, is_valid_coordinates_1, is_valid_coordinates_regular_expression, - word_squares + word_squares, + convert_morse_word, unique_morse, + judge_circle, + strong_password ) import unittest @@ -291,7 +294,7 @@ def test_pythonic(self): self.assertEqual("ereht olleh", pythonic("hello there")) def test_ultra_pythonic(self): self.assertEqual("ereht olleh", ultra_pythonic("hello there")) - + class TestReverseVowel(unittest.TestCase): """[summary] @@ -381,6 +384,22 @@ def test_word_squares(self): self.assertEqual([['wall', 'area', 'lead', 'lady'], ['ball', 'area', 'lead', 'lady']], \ word_squares(["area","lead","wall","lady","ball"])) +class TestUniqueMorse(unittest.TestCase): + def test_convert_morse_word(self): + self.assertEqual("--...-.", convert_morse_word("gin")) + self.assertEqual("--...--.", convert_morse_word("msg")) + def test_unique_morse(self): + self.assertEqual(2, unique_morse(["gin", "zen", "gig", "msg"])) + +class TestJudgeCircle(unittest.TestCase): + def test_judge_circle(self): + self.assertTrue(judge_circle("UDLRUD")) + self.assertFalse(judge_circle("LLRU")) + +class TestStrongPassword(unittest.TestCase): + def test_strong_password(self): + self.assertEqual(3, strong_password(3,"Ab1")) + self.assertEqual(1, strong_password(11,"#Algorithms")) if __name__ == "__main__": unittest.main() From 37bee74581cfc1b1ddb28ee5fe8da97bcd71c35a Mon Sep 17 00:00:00 2001 From: arsgsg1 Date: Tue, 19 Jun 2018 05:59:23 +0900 Subject: [PATCH 079/302] added combination_memo.py using memoization (#358) * Update combination.py * Update test_maths.py * fixed test_maths.py * update function combination_memo * update test of combination_memo --- algorithms/maths/combination.py | 13 ++++++++++++- tests/test_maths.py | 6 ++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/algorithms/maths/combination.py b/algorithms/maths/combination.py index ea9e4b37f..308b0bcc4 100644 --- a/algorithms/maths/combination.py +++ b/algorithms/maths/combination.py @@ -1,6 +1,17 @@ def combination(n, r): - # This function calculates nCr + """This function calculates nCr.""" if n == r or r == 0: return 1 else: return combination(n-1, r-1) + combination(n-1, r) + +def combination_memo(n, r): + """This function calculates nCr using memoization method.""" + memo = {} + def recur(n, r): + if n == r or r == 0: + return 1 + if (n, r) not in memo: + memo[(n, r)] = recur(n - 1, r - 1) + recur(n - 1, r) + return memo[(n, r)] + return recur(n, r) diff --git a/tests/test_maths.py b/tests/test_maths.py index 1514907fe..9270c28f5 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -12,7 +12,7 @@ pythagoras, is_prime, encrypt, decrypt, generate_key, - combination + combination, combination_memo ) import unittest @@ -230,7 +230,9 @@ class TestCombination(unittest.TestCase): def test_combination(self): self.assertEqual(10, combination(5, 2)) self.assertEqual(252, combination(10, 5)) - + def test_combination_memo(self): + self.assertEqual(10272278170, combination_memo(50, 10)) + self.assertEqual(847660528, combination_memo(40, 10)) class TestFactorial(unittest.TestCase): """[summary] Test for the file factorial.py From 5493bcda30f0b8ce390cf68de29f0dcdf0a17045 Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Mon, 18 Jun 2018 14:03:20 -0700 Subject: [PATCH 080/302] Add some String solution (#359) * Add unique morse * Add judge_circle * Add strong password * Add caesar cipher * Add contain string * Add count binary substring * Fix conflict --- README.md | 3 ++ algorithms/strings/__init__.py | 3 ++ algorithms/strings/caesar_cipher.py | 19 +++++++++++ algorithms/strings/contain_string.py | 25 +++++++++++++++ algorithms/strings/count_binary_substring.py | 33 ++++++++++++++++++++ tests/test_strings.py | 22 ++++++++++++- 6 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 algorithms/strings/caesar_cipher.py create mode 100644 algorithms/strings/contain_string.py create mode 100644 algorithms/strings/count_binary_substring.py diff --git a/README.md b/README.md index 73877e476..4aa68cf60 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,9 @@ If you want to uninstall algorithms, it is as simple as: - [unique_morse](algorithms/strings/unique_morse.py) - [judge_circle](algorithms/strings/judge_circle.py) - [strong_password](algorithms/strings/strong_password.py) + - [caesar_cipher](algorithms/strings/caesar_cipher.py) + - [contain_string](algorithms/strings/contain_string.py) + - [count_binary_substring](algorithms/strings/count_binary_substring.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index a74dbf06d..afeb60c3b 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -24,3 +24,6 @@ from .unique_morse import * from .judge_circle import * from .strong_password import * +from .caesar_cipher import * +from .contain_string import * +from .count_binary_substring import * diff --git a/algorithms/strings/caesar_cipher.py b/algorithms/strings/caesar_cipher.py new file mode 100644 index 000000000..379f63e0d --- /dev/null +++ b/algorithms/strings/caesar_cipher.py @@ -0,0 +1,19 @@ + +""" +Julius Caesar protected his confidential information by encrypting it using a cipher. +Caesar's cipher shifts each letter by a number of letters. If the shift takes you +past the end of the alphabet, just rotate back to the front of the alphabet. +In the case of a rotation by 3, w, x, y and z would map to z, a, b and c. +Original alphabet: abcdefghijklmnopqrstuvwxyz +Alphabet rotated +3: defghijklmnopqrstuvwxyzabc +""" +def caesar_cipher(s, k): + result = "" + for char in s: + n = ord(char) + if 64 < n < 91: + n = ((n - 65 + k) % 26) + 65 + if 96 < n < 123: + n = ((n - 97 + k) % 26) + 97 + result = result + chr(n) + return result diff --git a/algorithms/strings/contain_string.py b/algorithms/strings/contain_string.py new file mode 100644 index 000000000..67056fed6 --- /dev/null +++ b/algorithms/strings/contain_string.py @@ -0,0 +1,25 @@ +""" +Implement strStr(). + +Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. + +Example 1: +Input: haystack = "hello", needle = "ll" +Output: 2 + +Example 2: +Input: haystack = "aaaaa", needle = "bba" +Output: -1 +Reference: https://leetcode.com/problems/implement-strstr/description/ +""" +def contain_string(haystack, needle): + if len(needle) == 0: + return 0 + if len(needle) > len(haystack): + return -1 + for i in range(len(haystack)): + if len(haystack) - i < len(needle): + return -1 + if haystack[i:i+len(needle)] == needle: + return i + return -1 diff --git a/algorithms/strings/count_binary_substring.py b/algorithms/strings/count_binary_substring.py new file mode 100644 index 000000000..bd775ee53 --- /dev/null +++ b/algorithms/strings/count_binary_substring.py @@ -0,0 +1,33 @@ +""" +Give a string s, count the number of non-empty (contiguous) substrings that have + the same number of 0's and 1's, and all the 0's and all the 1's in these substrings are grouped consecutively. + +Substrings that occur multiple times are counted the number of times they occur. +Example 1: +Input: "00110011" +Output: 6 +Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01". + +Notice that some of these substrings repeat and are counted the number of times they occur. + +Also, "00110011" is not a valid substring because all the 0's (and 1's) are not grouped together. + +Example 2: +Input: "10101" +Output: 4 +Explanation: There are 4 substrings: "10", "01", "10", "01" that have equal number of consecutive 1's and 0's. +Reference: https://leetcode.com/problems/count-binary-substrings/description/ +""" +def count_binary_substring(s): + cur = 1 + pre = 0 + count = 0 + for i in range(1, len(s)): + if s[i] != s[i - 1]: + count = count + min(pre, cur) + pre = cur + cur = 1 + else: + cur = cur + 1 + count = count + min(pre, cur) + return count diff --git a/tests/test_strings.py b/tests/test_strings.py index 0cda82cc5..05d977bd1 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -26,7 +26,10 @@ word_squares, convert_morse_word, unique_morse, judge_circle, - strong_password + strong_password, + caesar_cipher, + contain_string, + count_binary_substring ) import unittest @@ -401,5 +404,22 @@ def test_strong_password(self): self.assertEqual(3, strong_password(3,"Ab1")) self.assertEqual(1, strong_password(11,"#Algorithms")) +class TestCaesarCipher(unittest.TestCase): + def test_caesar_cipher(self): + self.assertEqual("Lipps_Asvph!", caesar_cipher("Hello_World!", 4)) + self.assertEqual("okffng-Qwvb", caesar_cipher("middle-Outz", 2)) + +class TestContainString(unittest.TestCase): + def test_contain_string(self): + self.assertEqual(-1, contain_string("mississippi", "issipi")) + self.assertEqual(0, contain_string("Hello World", "")) + self.assertEqual(2, contain_string("hello", "ll")) + +class TestCountBinarySubstring(unittest.TestCase): + def test_count_binary_substring(self): + self.assertEqual(6, count_binary_substring("00110011")) + self.assertEqual(4, count_binary_substring("10101")) + self.assertEqual(3, count_binary_substring("00110")) + if __name__ == "__main__": unittest.main() From 6ad74b6be9e3a02f5e992af368db4c2dc51d9808 Mon Sep 17 00:00:00 2001 From: Edilson Alves Date: Wed, 20 Jun 2018 16:02:17 -0300 Subject: [PATCH 081/302] Correction in README files (#360) --- README.md | 2 +- README_GE.md | 2 +- README_JP.md | 2 +- README_KR.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4aa68cf60..3ba28d054 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ If you want to uninstall algorithms, it is as simple as: - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) -    - [rotate](algorithms/arrays/rotate.py) + - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [trimmean](algorithms/arrays/trimmean.py) diff --git a/README_GE.md b/README_GE.md index f9f475709..2760b2c76 100644 --- a/README_GE.md +++ b/README_GE.md @@ -73,7 +73,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) -    - [rotate](algorithms/arrays/rotate.py) + - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [trimmean](algorithms/arrays/trimmean.py) diff --git a/README_JP.md b/README_JP.md index 571c70fe7..900f8ee91 100644 --- a/README_JP.md +++ b/README_JP.md @@ -67,7 +67,7 @@ if __name__ == "__main__": - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) -    - [rotate](algorithms/arrays/rotate.py) + - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [trimmean](algorithms/arrays/trimmean.py) diff --git a/README_KR.md b/README_KR.md index 773babd94..daf736865 100644 --- a/README_KR.md +++ b/README_KR.md @@ -66,7 +66,7 @@ if __name__ == "__main__": - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) -    - [rotate](algorithms/arrays/rotate.py) + - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) - [trimmean](algorithms/arrays/trimmean.py) From 447e02d9d89bbab2763ab99aac87ee5277b957bc Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Fri, 22 Jun 2018 03:21:23 +0530 Subject: [PATCH 082/302] added exponential and some refactors to maths/ (#361) * added maths/modular_exponential.py and tests * cleared the requirements.txt * refactor math/factorial * refactor prime_check and sieve * added test_requirements.txt for travis --- .travis.yml | 2 +- README.md | 1 + README_CN.md | 1 + README_GE.md | 1 + README_JP.md | 1 + README_KR.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/extended_gcd.py | 13 ++-- algorithms/maths/factorial.py | 36 +++++++---- algorithms/maths/modular_exponential.py | 18 ++++++ algorithms/maths/nth_digit.py | 25 ++++---- algorithms/maths/prime_check.py | 27 ++------ .../maths/primes_sieve_of_eratosthenes.py | 32 ++++++---- algorithms/maths/rsa.py | 17 +++-- algorithms/maths/sqrt_precision_factor.py | 18 +++--- requirements.txt | 6 -- test_requirements.txt | 6 ++ tests/test_maths.py | 64 ++++++++++++------- 18 files changed, 155 insertions(+), 115 deletions(-) create mode 100644 algorithms/maths/modular_exponential.py create mode 100644 test_requirements.txt diff --git a/.travis.yml b/.travis.yml index 11468847b..e9a4450a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ matrix: - python: 3.6 env: TOX_ENV=py36 install: - - pip install -r requirements.txt + - pip install -r test_requirements.txt before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics diff --git a/README.md b/README.md index 3ba28d054..82286982c 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ If you want to uninstall algorithms, it is as simple as: - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) diff --git a/README_CN.md b/README_CN.md index 42f7b36d0..99fac2ae2 100644 --- a/README_CN.md +++ b/README_CN.md @@ -183,6 +183,7 @@ pip3 uninstall -y algorithms - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](algorithms/maths/primes_sieve_of_eratosthenes.py) - [generate_strobogrammtic:生成对称数](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic:判断对称数](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) - [nth_digit:第n位](algorithms/maths/nth_digit.py) - [rabin_miller:米勒-拉宾素性检验](algorithms/maths/rabin_miller.py) - [rsa:rsa加密](algorithms/maths/rsa.py) diff --git a/README_GE.md b/README_GE.md index 2760b2c76..a8f16ad65 100644 --- a/README_GE.md +++ b/README_GE.md @@ -193,6 +193,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) diff --git a/README_JP.md b/README_JP.md index 900f8ee91..86453b784 100644 --- a/README_JP.md +++ b/README_JP.md @@ -187,6 +187,7 @@ if __name__ == "__main__": - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) diff --git a/README_KR.md b/README_KR.md index daf736865..ccb7fad5a 100644 --- a/README_KR.md +++ b/README_KR.md @@ -184,6 +184,7 @@ if __name__ == "__main__": - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 543d8d355..177fed31d 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -5,6 +5,7 @@ from .gcd import * from .generate_strobogrammtic import * from .is_strobogrammatic import * +from .modular_exponential import * from .next_perfect_square import * from .prime_check import * from .primes_sieve_of_eratosthenes import * diff --git a/algorithms/maths/extended_gcd.py b/algorithms/maths/extended_gcd.py index 96c31ac65..83b657807 100644 --- a/algorithms/maths/extended_gcd.py +++ b/algorithms/maths/extended_gcd.py @@ -1,11 +1,10 @@ -""" -extended GCD algorithm -return s,t,g -such that a s + b t = GCD(a, b) -and s and t are coprime -""" +def extended_gcd(a, b): + """Extended GCD algorithm. + Return s, t, g + such that a * s + b * t = GCD(a, b) + and s and t are co-prime. + """ -def extended_gcd(a,b): old_s, s = 1, 0 old_t, t = 0, 1 old_r, r = a, b diff --git a/algorithms/maths/factorial.py b/algorithms/maths/factorial.py index 2cd1a3491..23e1f5354 100644 --- a/algorithms/maths/factorial.py +++ b/algorithms/maths/factorial.py @@ -1,20 +1,32 @@ -# -# This function calculates n! -# Factorial function not works in less than 0 -# - -def factorial(n): - +def factorial(n, mod=None): + """Calculates factorial iteratively. + If mod is not None, then return (n! % mod) + Time Complexity - O(n)""" + if not (isinstance(n, int) and n >= 0): + raise ValueError("'n' must be a non-negative integer.") + if mod is not None and not (isinstance(mod, int) and mod > 0): + raise ValueError("'mod' must be a positive integer") result = 1 + if n == 0: + return 1 for i in range(2, n+1): result *= i - + if mod: + result %= mod return result -def factorial_recur(n): +def factorial_recur(n, mod=None): + """Calculates factorial recursively. + If mod is not None, then return (n! % mod) + Time Complexity - O(n)""" + if not (isinstance(n, int) and n >= 0): + raise ValueError("'n' must be a non-negative integer.") + if mod is not None and not (isinstance(mod, int) and mod > 0): + raise ValueError("'mod' must be a positive integer") if n == 0: return 1 - - return n * factorial(n-1) - + result = n * factorial(n - 1, mod) + if mod: + result %= mod + return result diff --git a/algorithms/maths/modular_exponential.py b/algorithms/maths/modular_exponential.py new file mode 100644 index 000000000..f0e58de8f --- /dev/null +++ b/algorithms/maths/modular_exponential.py @@ -0,0 +1,18 @@ +def modular_exponential(base, exponent, mod): + """Computes (base ^ exponent) % mod. + Time complexity - O(log n) + Use similar to Python in-built function pow.""" + if exponent < 0: + raise ValueError("Exponent must be positive.") + base %= mod + result = 1 + + while exponent > 0: + # If the last bit is 1, add 2^k. + if exponent & 1: + result = (result * base) % mod + exponent = exponent >> 1 + # Utilize modular multiplication properties to combine the computed mod C values. + base = (base * base) % mod + + return result diff --git a/algorithms/maths/nth_digit.py b/algorithms/maths/nth_digit.py index ea2d6819e..381926f3e 100644 --- a/algorithms/maths/nth_digit.py +++ b/algorithms/maths/nth_digit.py @@ -1,20 +1,17 @@ -""" -find nth digit -1. find the length of the number where the nth digit is from. -2. find the actual number where the nth digit is from -3. find the nth digit and return -""" - - def find_nth_digit(n): - len = 1 + """find the nth digit of given number. + 1. find the length of the number where the nth digit is from. + 2. find the actual number where the nth digit is from + 3. find the nth digit and return + """ + length = 1 count = 9 start = 1 - while n > len * count: - n -= len * count - len += 1 + while n > length * count: + n -= length * count + length += 1 count *= 10 start *= 10 - start += (n-1) / len + start += (n-1) / length s = str(start) - return int(s[(n-1) % len]) \ No newline at end of file + return int(s[(n-1) % length]) \ No newline at end of file diff --git a/algorithms/maths/prime_check.py b/algorithms/maths/prime_check.py index 1821d250b..60e4427ab 100644 --- a/algorithms/maths/prime_check.py +++ b/algorithms/maths/prime_check.py @@ -1,8 +1,8 @@ -""" -prime_test(n) returns a True if n is a prime number else it returns False -""" - def prime_check(n): + """Return True if n is a prime number + Else return False. + """ + if n <= 1: return False if n == 2 or n == 3: @@ -15,22 +15,3 @@ def prime_check(n): return False j += 6 return True - - -def prime_check2(n): - # prime numbers are greater than 1 - if n > 1: - # check for factors - for i in range(2, int(n ** 0.5) + 1): - if (n % i) == 0: - # print(num, "is not a prime number") - # print(i, "times", num//i, "is", num) - return False - - # print(num, "is a prime number") - return True - - # if input number is less than - # or equal to 1, it is not prime - else: - return False diff --git a/algorithms/maths/primes_sieve_of_eratosthenes.py b/algorithms/maths/primes_sieve_of_eratosthenes.py index 1677b2575..7c21c6d82 100644 --- a/algorithms/maths/primes_sieve_of_eratosthenes.py +++ b/algorithms/maths/primes_sieve_of_eratosthenes.py @@ -1,11 +1,12 @@ -''' -Using sieve of Eratosthenes, primes(x) returns list of all primes less than x +""" +Return list of all primes less than n, +Using sieve of Eratosthenes. Modification: We don't need to check all even numbers, we can make the sieve excluding even numbers and adding 2 to the primes list by default. -We are going to make an array of: x / 2 - 1 if number is even, else x / 2 +We are going to make an array of: x / 2 - 1 if number is even, else x / 2 (The -1 with even number it's to exclude the number itself) Because we just need numbers [from 3..x if x is odd] @@ -21,20 +22,25 @@ With this, we have reduced the array size to a half, and complexity it's also a half now. -''' +""" -def primes(x): - assert(x >= 0) + +def get_primes(n): + """Return list of all primes less than n, + Using sieve of Eratosthenes. + """ + if n <= 0: + raise ValueError("'n' must be a positive integer.") # If x is even, exclude x from list (-1): - sieve_size = (x//2 - 1) if x % 2 == 0 else (x//2) - sieve = [1 for v in range(sieve_size)] # Sieve - primes = [] # List of Primes - if x >= 2: - primes.append(2) # Add 2 by default + sieve_size = (n // 2 - 1) if n % 2 == 0 else (n // 2) + sieve = [True for _ in range(sieve_size)] # Sieve + primes = [] # List of Primes + if n >= 2: + primes.append(2) # 2 is prime by default for i in range(sieve_size): - if sieve[i] == 1: + if sieve[i]: value_at_i = i*2 + 3 primes.append(value_at_i) for j in range(i, sieve_size, value_at_i): - sieve[j] = 0 + sieve[j] = False return primes diff --git a/algorithms/maths/rsa.py b/algorithms/maths/rsa.py index e3f29956c..70b7bc5cc 100644 --- a/algorithms/maths/rsa.py +++ b/algorithms/maths/rsa.py @@ -24,21 +24,20 @@ import random -def modinv(a, m): - """calculate the inverse of a mod m - that is, find b such that (a * b) % m == 1""" - b = 1 - while not (a * b) % m == 1: - b += 1 - return b - - def generate_key(k, seed=None): """ the RSA key generating algorithm k is the number of bits in n """ + def modinv(a, m): + """calculate the inverse of a mod m + that is, find b such that (a * b) % m == 1""" + b = 1 + while not (a * b) % m == 1: + b += 1 + return b + def gen_prime(k, seed=None): """generate a prime with k bits""" diff --git a/algorithms/maths/sqrt_precision_factor.py b/algorithms/maths/sqrt_precision_factor.py index ce4f0cf94..bb47c0945 100644 --- a/algorithms/maths/sqrt_precision_factor.py +++ b/algorithms/maths/sqrt_precision_factor.py @@ -1,17 +1,19 @@ """ Given a positive integer N and a precision factor P, -write a square root function that produce an output +it produces an output with a maximum error P from the actual square root of N. Example: -Given N = 5 and P = 0.001, can produce output O such that -2.235 < O > 2.237. Actual square root of 5 being 2.236. +Given N = 5 and P = 0.001, can produce output x such that +2.235 < x < 2.237. Actual square root of 5 being 2.236. """ -def square_root(n,p): - guess = float(n) / 2 - while abs(guess * guess - n) > p: - guess = (guess + (n / guess)) / 2 +def square_root(n, epsilon=0.001): + """Return square root of n, with maximum absolute error epsilon""" + guess = n / 2 - return guess + while abs(guess * guess - n) > epsilon: + guess = (guess + (n / guess)) / 2 + + return guess diff --git a/requirements.txt b/requirements.txt index 7a3e47c8a..e69de29bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +0,0 @@ -flake8 -python-coveralls -coverage -nose -pytest -tox diff --git a/test_requirements.txt b/test_requirements.txt new file mode 100644 index 000000000..7a3e47c8a --- /dev/null +++ b/test_requirements.txt @@ -0,0 +1,6 @@ +flake8 +python-coveralls +coverage +nose +pytest +tox diff --git a/tests/test_maths.py b/tests/test_maths.py index 9270c28f5..2499a4f88 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -6,12 +6,13 @@ gcd, lcm, gen_strobogrammatic, strobogrammatic_in_range, is_strobogrammatic, is_strobogrammatic2, + modular_exponential, find_next_square, find_next_square2, - prime_check, prime_check2, - primes, + prime_check, + get_primes, pythagoras, is_prime, - encrypt, decrypt, generate_key, + encrypt, decrypt, combination, combination_memo ) @@ -46,9 +47,12 @@ class TestDecimalToBinaryIP(unittest.TestCase): """ def test_decimal_to_binary_ip(self): - self.assertEqual("00000000.00000000.00000000.00000000", decimal_to_binary_ip("0.0.0.0")) - self.assertEqual("11111111.11111111.11111111.11111111", decimal_to_binary_ip("255.255.255.255")) - self.assertEqual("11000000.10101000.00000000.00000001", decimal_to_binary_ip("192.168.0.1")) + self.assertEqual("00000000.00000000.00000000.00000000", + decimal_to_binary_ip("0.0.0.0")) + self.assertEqual("11111111.11111111.11111111.11111111", + decimal_to_binary_ip("255.255.255.255")) + self.assertEqual("11000000.10101000.00000000.00000001", + decimal_to_binary_ip("192.168.0.1")) class TestExtendedGcd(unittest.TestCase): @@ -112,6 +116,22 @@ def test_is_strobogrammatic2(self): self.assertFalse(is_strobogrammatic2("14")) +class TestModularExponential(unittest.TestCase): + """[summary] + Test for the file modular_Exponential.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_modular_exponential(self): + self.assertEqual(1, modular_exponential(5, 117, 19)) + self.assertEqual(pow(1243, 65321, 10**9 + 7), + modular_exponential(1243, 65321, 10**9 + 7)) + self.assertEqual(1, modular_exponential(12, 0, 78)) + self.assertRaises(ValueError, modular_exponential, 12, -2, 455) + + class TestNextPerfectSquare(unittest.TestCase): """[summary] Test for the file next_perfect_square.py @@ -138,7 +158,8 @@ class TestPrimesSieveOfEratosthenes(unittest.TestCase): """ def test_primes(self): - self.assertEqual([2, 3, 5, 7], primes(7)) + self.assertListEqual([2, 3, 5, 7], get_primes(7)) + self.assertRaises(ValueError, get_primes, -42) class TestPrimeTest(unittest.TestCase): @@ -160,17 +181,6 @@ def test_prime_test(self): counter += 1 self.assertEqual(25, counter) - def test_prime_test2(self): - """ - checks all prime numbers between 2 up to 100. - Between 2 up to 100 exists 25 prime numbers! - """ - counter = 0 - for i in range(2, 101): - if prime_check2(i): - counter += 1 - self.assertEqual(25, counter) - class TestPythagoras(unittest.TestCase): """[summary] @@ -219,6 +229,7 @@ def test_encrypt_decrypt(self): # dec = decrypt(en, d, n) # self.assertEqual(data,dec) + class TestCombination(unittest.TestCase): """[summary] Test for the file combination.py @@ -230,9 +241,12 @@ class TestCombination(unittest.TestCase): def test_combination(self): self.assertEqual(10, combination(5, 2)) self.assertEqual(252, combination(10, 5)) + def test_combination_memo(self): self.assertEqual(10272278170, combination_memo(50, 10)) self.assertEqual(847660528, combination_memo(40, 10)) + + class TestFactorial(unittest.TestCase): """[summary] Test for the file factorial.py @@ -245,13 +259,19 @@ def test_factorial(self): self.assertEqual(1, factorial(0)) self.assertEqual(120, factorial(5)) self.assertEqual(3628800, factorial(10)) - + self.assertEqual(637816310, factorial(34521, 10**9 + 7)) + self.assertRaises(ValueError, factorial, -42) + self.assertRaises(ValueError, factorial, 42, -1) + def test_factorial_recur(self): self.assertEqual(1, factorial_recur(0)) self.assertEqual(120, factorial_recur(5)) self.assertEqual(3628800, factorial_recur(10)) - + self.assertEqual(637816310, factorial_recur(34521, 10**9 + 7)) + self.assertRaises(ValueError, factorial_recur, -42) + self.assertRaises(ValueError, factorial_recur, 42, -1) + + if __name__ == "__main__": unittest.main() - - + From 7520795db8a40f40942454116357d2b9262a552b Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Wed, 27 Jun 2018 11:39:13 -0700 Subject: [PATCH 083/302] Added some solution (#362) * Add simplify path * Add repeat string --- README.md | 2 ++ algorithms/strings/__init__.py | 1 + algorithms/strings/repeat_string.py | 24 ++++++++++++++++++++++ algorithms/unix/__init__.py | 1 + algorithms/unix/path/simplify_path.py | 29 +++++++++++++++++++++++++++ tests/test_strings.py | 8 +++++++- tests/test_unix.py | 9 ++++++++- 7 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 algorithms/strings/repeat_string.py create mode 100644 algorithms/unix/path/simplify_path.py diff --git a/README.md b/README.md index 82286982c..abc9f5503 100644 --- a/README.md +++ b/README.md @@ -291,6 +291,7 @@ If you want to uninstall algorithms, it is as simple as: - [caesar_cipher](algorithms/strings/caesar_cipher.py) - [contain_string](algorithms/strings/contain_string.py) - [count_binary_substring](algorithms/strings/count_binary_substring.py) + - [repeat_string](algorithms/strings/repeat_string.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) @@ -343,6 +344,7 @@ If you want to uninstall algorithms, it is as simple as: - [join_with_slash](algorithms/unix/path/join_with_slash.py) - [full_path](algorithms/unix/path/full_path.py) - [split](algorithms/unix/path/split.py) + - [simplify_path](algorithms/unix/path/simplify_path.py) - [union-find](algorithms/union-find) - [count_islands](algorithms/union-find/count_islands.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index afeb60c3b..4040c9e85 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -27,3 +27,4 @@ from .caesar_cipher import * from .contain_string import * from .count_binary_substring import * +from .repeat_string import * diff --git a/algorithms/strings/repeat_string.py b/algorithms/strings/repeat_string.py new file mode 100644 index 000000000..cc871f64c --- /dev/null +++ b/algorithms/strings/repeat_string.py @@ -0,0 +1,24 @@ +""" +Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1. + +For example, with A = "abcd" and B = "cdabcdab". + +Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times ("abcdabcd"). + +Note: +The length of A and B will be between 1 and 10000. + +Reference: https://leetcode.com/problems/repeated-string-match/description/ +""" +def repeat_string(A, B): + count = 1 + tmp = A + max_count = (len(B) / len(A)) + 1 + while not(B in tmp): + tmp = tmp + A + if (count > max_count): + count = -1 + break + count = count + 1 + + return count diff --git a/algorithms/unix/__init__.py b/algorithms/unix/__init__.py index 68b785c97..0d1808da0 100644 --- a/algorithms/unix/__init__.py +++ b/algorithms/unix/__init__.py @@ -1,3 +1,4 @@ from .path.join_with_slash import * from .path.full_path import * from .path.split import * +from .path.simplify_path import * diff --git a/algorithms/unix/path/simplify_path.py b/algorithms/unix/path/simplify_path.py new file mode 100644 index 000000000..8880fc0c6 --- /dev/null +++ b/algorithms/unix/path/simplify_path.py @@ -0,0 +1,29 @@ +""" +Given an absolute path for a file (Unix-style), simplify it. + +For example, +path = "/home/", => "/home" +path = "/a/./b/../../c/", => "/c" + +Corner Cases: + +Did you consider the case where path = "/../"? +In this case, you should return "/". +Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". +In this case, you should ignore redundant slashes and return "/home/foo". + +Reference: https://leetcode.com/problems/simplify-path/description/ +""" + +import os +def simplify_path_v1(path): + return os.path.abspath(path) + +def simplify_path_v2(path): + stack, tokens = [], path.split("/") + for token in tokens: + if token == ".." and stack: + stack.pop() + elif token != ".." and token != "." and token: + stack.append(token) + return "/" + "/".join(stack) diff --git a/tests/test_strings.py b/tests/test_strings.py index 05d977bd1..c8b918280 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -29,7 +29,8 @@ strong_password, caesar_cipher, contain_string, - count_binary_substring + count_binary_substring, + repeat_string ) import unittest @@ -421,5 +422,10 @@ def test_count_binary_substring(self): self.assertEqual(4, count_binary_substring("10101")) self.assertEqual(3, count_binary_substring("00110")) +class TestCountBinarySubstring(unittest.TestCase): + def test_repeat_string(self): + self.assertEqual(3, repeat_string("abcd","cdabcdab")) + self.assertEqual(4, repeat_string("bb", "bbbbbbb")) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_unix.py b/tests/test_unix.py index a24388970..e7a6c6349 100644 --- a/tests/test_unix.py +++ b/tests/test_unix.py @@ -1,7 +1,8 @@ from algorithms.unix import ( join_with_slash, full_path, - split + split, + simplify_path_v1, simplify_path_v2 ) import os import unittest @@ -33,3 +34,9 @@ def test_split(self): expect_result = split(path) self.assertEqual("algorithms/unix", expect_result[0]) self.assertEqual("test.py", expect_result[1]) + + def test_simplify_path(self): + self.assertEqual("/", simplify_path_v1("/../")) + self.assertEqual("/home/foo", simplify_path_v1("/home//foo/")) + self.assertEqual("/", simplify_path_v2("/../")) + self.assertEqual("/home/foo", simplify_path_v2("/home//foo/")) From 81e78536d4cad1519d5ffd18b79b616ec53f63bb Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Thu, 28 Jun 2018 14:38:03 -0500 Subject: [PATCH 084/302] #256 change strip_url_params3 to use OrderedDict to prevent failing test on non deterministic retrieval of dict keys for query string (#367) --- algorithms/strings/strip_url_params.py | 4 ++- tests/test_strings.py | 34 +++++++++++++------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/algorithms/strings/strip_url_params.py b/algorithms/strings/strip_url_params.py index 364f78091..d2821a69f 100644 --- a/algorithms/strings/strip_url_params.py +++ b/algorithms/strings/strip_url_params.py @@ -10,6 +10,8 @@ import urllib import urllib.parse +from collections import OrderedDict + # Here is a very non-pythonic grotesque solution def strip_url_params1(url, params_to_strip=None): @@ -37,7 +39,7 @@ def strip_url_params1(url, params_to_strip=None): string = '' else: string += char - dict = defaultdict(int) + dict = OrderedDict() # logic for checking whether we should add the string to our result for i in key_value_string: _token = i.split('=') diff --git a/tests/test_strings.py b/tests/test_strings.py index c8b918280..69c05b315 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -339,23 +339,23 @@ def test_roman_to_int(self): self.assertEqual(3999, roman_to_int("MMMCMXCIX")) -# class TestStripUrlParams(unittest.TestCase): -# """[summary] -# Test for the file strip_urls_params.py - -# Arguments: -# unittest {[type]} -- [description] -# """ - -# def test_strip_url_params1(self): -# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") -# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") -# def test_strip_url_params2(self): -# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") -# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") -# def test_strip_url_params3(self): -# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") -# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +class TestStripUrlParams(unittest.TestCase): + """[summary] + Test for the file strip_urls_params.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_strip_url_params1(self): + self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") + self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") + def test_strip_url_params2(self): + self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") + self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") + def test_strip_url_params3(self): + self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") + self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") class TestValidateCoordinates(unittest.TestCase): From a289b6bf1ce2e286627ddd077b12d2e71f4030f0 Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Thu, 28 Jun 2018 16:44:34 -0700 Subject: [PATCH 085/302] Revert "#256 change strip_url_params3 to use OrderedDict to prevent failing test on non deterministic retrieval of dict keys for query string (#367)" (#368) This reverts commit 81e78536d4cad1519d5ffd18b79b616ec53f63bb. --- algorithms/strings/strip_url_params.py | 4 +-- tests/test_strings.py | 34 +++++++++++++------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/algorithms/strings/strip_url_params.py b/algorithms/strings/strip_url_params.py index d2821a69f..364f78091 100644 --- a/algorithms/strings/strip_url_params.py +++ b/algorithms/strings/strip_url_params.py @@ -10,8 +10,6 @@ import urllib import urllib.parse -from collections import OrderedDict - # Here is a very non-pythonic grotesque solution def strip_url_params1(url, params_to_strip=None): @@ -39,7 +37,7 @@ def strip_url_params1(url, params_to_strip=None): string = '' else: string += char - dict = OrderedDict() + dict = defaultdict(int) # logic for checking whether we should add the string to our result for i in key_value_string: _token = i.split('=') diff --git a/tests/test_strings.py b/tests/test_strings.py index 69c05b315..c8b918280 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -339,23 +339,23 @@ def test_roman_to_int(self): self.assertEqual(3999, roman_to_int("MMMCMXCIX")) -class TestStripUrlParams(unittest.TestCase): - """[summary] - Test for the file strip_urls_params.py - - Arguments: - unittest {[type]} -- [description] - """ - - def test_strip_url_params1(self): - self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") - self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") - def test_strip_url_params2(self): - self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") - self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") - def test_strip_url_params3(self): - self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") - self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +# class TestStripUrlParams(unittest.TestCase): +# """[summary] +# Test for the file strip_urls_params.py + +# Arguments: +# unittest {[type]} -- [description] +# """ + +# def test_strip_url_params1(self): +# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") +# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +# def test_strip_url_params2(self): +# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") +# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +# def test_strip_url_params3(self): +# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") +# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") class TestValidateCoordinates(unittest.TestCase): From c9cfdef3a04e317a02381c4f80053533fa8b1d37 Mon Sep 17 00:00:00 2001 From: Ernest Date: Fri, 29 Jun 2018 16:00:23 +0800 Subject: [PATCH 086/302] Implemented n sum (#365) * Implement N sum * Add N sum test * Add docstring * Add n num link * Rearrange code * Fix import error * Move functions to inner * Fix coding style * Rename * Separate logic * Add advanced usage example * Add test * Fix error: cannot hash list object when user's nums is a list of list * Add parameters docstring --- README.md | 1 + algorithms/arrays/__init__.py | 1 + algorithms/arrays/n_sum.py | 129 ++++++++++++++++++++++++++++++++++ tests/test_array.py | 36 ++++++++-- 4 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 algorithms/arrays/n_sum.py diff --git a/README.md b/README.md index abc9f5503..80de0529f 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ If you want to uninstall algorithms, it is as simple as: - [top_1](algorithms/arrays/top_1.py) - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) + - [n_sum](algorithms/arrays/n_sum.py) - [backtrack](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [anagram](algorithms/backtrack/anagram.py) diff --git a/algorithms/arrays/__init__.py b/algorithms/arrays/__init__.py index c0d8b8f23..9670db750 100644 --- a/algorithms/arrays/__init__.py +++ b/algorithms/arrays/__init__.py @@ -15,3 +15,4 @@ from .top_1 import * from .two_sum import * from .limit import * +from .n_sum import * diff --git a/algorithms/arrays/n_sum.py b/algorithms/arrays/n_sum.py new file mode 100644 index 000000000..a01348e57 --- /dev/null +++ b/algorithms/arrays/n_sum.py @@ -0,0 +1,129 @@ +""" +Given an array of n integers, are there elements a, b, .. , n in nums +such that a + b + .. + n = target? + +Find all unique triplets in the array which gives the sum of target. + +Example: + basic: + Given: + n = 4, nums = [1, 0, -1, 0, -2, 2], target = 0, + return [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]] + + advanced: + Given: + n = 2 + nums = [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]] + taget = -5 + def sum(a, b): + return [a[0] + b[1], a[1] + b[0]] + def compare(num, taget): + if num[0] < taget: + return -1 + elif if num[0] > taget: + return 1 + else: + return 0 + return [[-9, 5], [8, 4]] + because -9 + 4 = -5 +""" + + +def n_sum(n, nums, target, **kv): + """ + n: int + nums: list[object] + target: object + sum_closure: function, optional + Given two elements of nums, return sum of both. + compare_closure: function, optional + Given one object of nums and target, return one of -1, 1, or 0. + same_closure: function, optional + Given two object of nums, return bool. + return: list[list[object]] + + Note: + 1. type of sum_closure's return should be same as type of compare_closure's first param + """ + + def sum_closure_default(a, b): + return a + b + + def compare_closure_default(num, taget): + if num < taget: + return -1 + elif num > taget: + return 1 + else: + return 0 + + def same_closure_default(a, b): + return a == b + + def n_sum(n, nums, target): + if n == 2: + results = two_sum(nums, target) + else: + results = [] + prev_num = None + for index, num in enumerate(nums): + if prev_num is not None and \ + same_closure(prev_num, num): + continue + prev_num = num + n_minus1_results = n_sum(n - 1, + nums[index + 1:], + target - num) + n_minus1_results = append_elem_to_each_list(num, + n_minus1_results) + results += n_minus1_results + return union(results) + + def two_sum(nums, target): + nums.sort() + lt = 0 + rt = len(nums) - 1 + results = [] + while lt < rt: + sum_ = sum_closure(nums[lt], nums[rt]) + flag = compare_closure(sum_, target) + if flag == -1: + lt += 1 + elif flag == 1: + rt -= 1 + else: + results.append(sorted([nums[lt], nums[rt]])) + lt += 1 + rt -= 1 + while (lt < len(nums) and + same_closure(nums[lt - 1], nums[lt])): + lt += 1 + while (0 <= rt and + same_closure(nums[rt], nums[rt + 1])): + rt -= 1 + return results + + def append_elem_to_each_list(elem, container): + results = [] + for elems in container: + elems.append(elem) + results.append(sorted(elems)) + return results + + def union(duplicate_results): + results = [] + + if len(duplicate_results) != 0: + duplicate_results.sort() + results.append(duplicate_results[0]) + for result in duplicate_results[1:]: + if results[-1] != result: + results.append(result) + + return results + + sum_closure = kv.get('sum_closure', sum_closure_default) + same_closure = kv.get('same_closure', same_closure_default) + compare_closure = kv.get('compare_closure', compare_closure_default) + nums.sort() + return n_sum(n, nums, target) diff --git a/tests/test_array.py b/tests/test_array.py index 6002adb43..47e24347a 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -15,7 +15,8 @@ max_ones_index, trimmean, top_1, - limit + limit, + n_sum ) import unittest @@ -309,28 +310,51 @@ def test_two_sum(self): self.assertTupleEqual((0, 3), two_sum([-3, 5, 2, 3, 8, -9], target=0)) self.assertIsNone(two_sum([-3, 5, 2, 3, 8, -9], target=6)) - + + class TestTrimmean(unittest.TestCase): def test_trimmean(self): self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 20), 5.5) self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 20), 6.0) - + + class TestTop1(unittest.TestCase): - + def test_top_1(self): self.assertListEqual(top_1([1 , 1, 2, 2, 3]), [1, 2]) self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), [23]) + class TestLimit(unittest.TestCase): - + def test_limit(self): self.assertListEqual(limit([1, 2, 3, 4, 5], 2, 4), [2, 3, 4]) self.assertListEqual(limit([1, 2, 3, 4, 5], 2), [2, 3, 4, 5]) self.assertListEqual(limit([1, 2, 3, 4, 5], None, 4), [1, 2, 3, 4]) - + +class TestNSum(unittest.TestCase): + + def test_n_sum(self): + self.assertEqual(n_sum(2, [-3, 5, 2, 3, 8, -9], 6), []) # noqa: E501 + self.assertEqual(n_sum(3, [-5, -4, -3, -2, -1, 0, 1, 2, 3], 0), sorted([[-5,2,3],[-2,0,2],[-4,1,3],[-3,1,2],[-1,0,1],[-2,-1,3],[-3,0,3]])) # noqa: E501 + self.assertEqual(n_sum(3, [-1,0,1,2,-1,-4], 0), sorted([[-1,-1,2],[-1,0,1]])) # noqa: E501 + self.assertEqual(n_sum(4, [1, 0, -1, 0, -2, 2], 0), sorted([[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]])) # noqa: E501 + self.assertEqual(n_sum(4, [7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 6, 4, -3, -2], 10), sorted([[-6, 2, 7, 7], [-6, 3, 6, 7], [-6, 4, 5, 7], [-6, 4, 6, 6], [-5, 1, 7, 7], [-5, 2, 6, 7], [-5, 3, 5, 7], [-5, 3, 6, 6], [-5, 4, 4, 7], [-5, 4, 5, 6], [-4, 0, 7, 7], [-4, 1, 6, 7], [-4, 2, 5, 7], [-4, 2, 6, 6], [-4, 3, 4, 7], [-4, 3, 5, 6], [-4, 4, 4, 6], [-3, -1, 7, 7], [-3, 0, 6, 7], [-3, 1, 5, 7], [-3, 1, 6, 6], [-3, 2, 4, 7], [-3, 2, 5, 6], [-3, 3, 4, 6], [-3, 4, 4, 5], [-2, -2, 7, 7], [-2, -1, 6, 7], [-2, 0, 5, 7], [-2, 0, 6, 6], [-2, 1, 4, 7], [-2, 1, 5, 6], [-2, 2, 3, 7], [-2, 2, 4, 6], [-2, 3, 4, 5], [-1, 0, 4, 7], [-1, 0, 5, 6], [-1, 1, 3, 7], [-1, 1, 4, 6], [-1, 2, 3, 6], [-1, 2, 4, 5], [-1, 3, 4, 4], [0, 1, 2, 7], [0, 1, 3, 6], [0, 1, 4, 5], [0, 2, 3, 5], [0, 2, 4, 4], [1, 2, 3, 4]])) # noqa: E501 + + self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], 0, # noqa: E501 + sum_closure=lambda a, b: a[0] + b[0]), # noqa: E501 + [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]]) # noqa: E501 + self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], [0, 3], # noqa: E501 + sum_closure=lambda a, b: [a[0] + b[0], a[1] + b[1]], # noqa: E501 + same_closure=lambda a, b: a[0] == b[0] and a[1] == b[1]), # noqa: E501 + [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]]) # noqa: E501 + self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], -5, # noqa: E501 + sum_closure=lambda a, b: [a[0] + b[1], a[1] + b[0]], # noqa: E501 + compare_closure=lambda a, b: -1 if a[0] < b else 1 if a[0] > b else 0), # noqa: E501 + [[[-9, 5], [8, 4]]]) # noqa: E501 if __name__ == '__main__': From 2d3faffc21096cfec4b4871e94ad6972aa5f16c8 Mon Sep 17 00:00:00 2001 From: Edilson Alves Date: Sat, 30 Jun 2018 12:49:31 -0300 Subject: [PATCH 087/302] Created README file in Brazilian Portuguese (#370) * Created README file in Brazilian Portuguese * Added link to README_PTBR.md --- README.md | 2 +- README_CN.md | 2 +- README_GE.md | 2 +- README_JP.md | 2 +- README_KR.md | 2 +- README_PTBR.md | 359 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 364 insertions(+), 5 deletions(-) create mode 100644 README_PTBR.md diff --git a/README.md b/README.md index 80de0529f..e8c4e80b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +English | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_CN.md b/README_CN.md index 99fac2ae2..b2fe38fd2 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@

-[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_GE.md b/README_GE.md index a8f16ad65..74769576a 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) +[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_JP.md b/README_JP.md index 86453b784..1fea3b826 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) +[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_KR.md b/README_KR.md index ccb7fad5a..52c7da65f 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 한국어 | [日本語](README_JP.md) +[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_PTBR.md b/README_PTBR.md new file mode 100644 index 000000000..6a4973af3 --- /dev/null +++ b/README_PTBR.md @@ -0,0 +1,359 @@ +

+ +[English](README.md) | Brazilian Portuguese | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) + +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) +[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + +Estruturas de Dados e Algoritmos Pythonicos +========================================= + +Exemplos de implementações mínimas e limpas de estruturas de dados e algoritmos em Python 3. + +## Contribuir +Obrigado pelo seu interesse em contribuir! Há muitas maneiras de contribuir para este projeto. [Comece aqui](CONTRIBUTING.md) + + +## Testes + +### Usando unittest +Para executar todos os testes, digite: + + $ python3 -m unittest discover tests + +Para executar algum teste específico, você pode fazer isso da seguinte maneira (Ex.: sort): + + $ python3 -m unittest tests.test_sort + +### Usando pytest +Para executar todos os testes, digite: + + $ python3 -m pytest tests + +## Instalar +Se você quiser usar os algoritmos da API em seu código, é tão simples quanto: + + $ pip3 install algorithms + +Você pode testar criando um arquivo python: (Ex.: usando `merge_sort` em `sort`) + +```python3 +from algorithms.sort import merge_sort + +if __name__ == "__main__": + my_list = [1, 8, 3, 5, 6] + my_list = merge_sort(my_list) + print(my_list) +``` + +## Desinstalar +Se você deseja desinstalar os algoritmos, é tão simples quanto: + + $ pip3 uninstall -y algorithms + +## Lista de Implementações + +- [arrays](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) + - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros](algorithms/arrays/move_zeros.py) +- [backtrack](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit](algorithms/bit) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_difference](algorithms/bit/find_difference.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) +- [calculator](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) + - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) +- [maths](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) + - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurance](algorithms/search/first_occurance.py) + - [last_occurance](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) +- [set](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) +- [sort](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) + - [bogo_sort](algorithms/sort/bogo_sort.py) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [top_sort](algorithms/sort/top_sort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) + - [unique_morse](algorithms/strings/unique_morse.py) + - [judge_circle](algorithms/strings/judge_circle.py) + - [strong_password](algorithms/strings/strong_password.py) + - [caesar_cipher](algorithms/strings/caesar_cipher.py) + - [contain_string](algorithms/strings/contain_string.py) + - [count_binary_substring](algorithms/strings/count_binary_substring.py) +- [tree](algorithms/tree) + - [bst](algorithms/tree/tree/bst) + - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bintree2list](algorithms/tree/bintree2list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [unix](algorithms/unix) + - [path](algorithms/unix/path/) + - [join_with_slash](algorithms/unix/path/join_with_slash.py) + - [full_path](algorithms/unix/path/full_path.py) + - [split](algorithms/unix/path/split.py) +- [union-find](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) + +## Contribuidores +O repositório é mantido por + +* [Keon Kim](https://github.com/keon) +* [Rahul Goswami](https://github.com/goswami-rahul) +* [Christian Bender](https://github.com/christianbender) +* [Ankit Agarwal](https://github.com/ankit167) +* [Hai Hoang Dang](https://github.com/danghai) +* [Saad](https://github.com/SaadBenn) + +Obrigado a [todos os contribuidores](https://github.com/keon/algorithms/graphs/contributors) +que ajudaram na construção do repositório. From 78fc4a0535cdfd0669f1db60087a5ef706fc7ac6 Mon Sep 17 00:00:00 2001 From: Edilson Alves Date: Mon, 9 Jul 2018 07:44:01 -0300 Subject: [PATCH 088/302] Corrected language title (#372) --- README.md | 3 +-- README_CN.md | 2 +- README_GE.md | 4 ++-- README_JP.md | 2 +- README_KR.md | 3 +-- README_PTBR.md | 3 +-- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e8c4e80b7..8a0ef8e61 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-English | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) @@ -15,7 +15,6 @@ Minimal and clean example implementations of data structures and algorithms in P ## Contributing Thanks for your interest in contributing! There are many ways to contribute to this project. [Get started here](CONTRIBUTING.md) - ## Tests ### Use unittest diff --git a/README_CN.md b/README_CN.md index b2fe38fd2..f3dc87fe9 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@

-[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_GE.md b/README_GE.md index 74769576a..226deee2c 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,6 +1,6 @@

-[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) +[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) @@ -14,7 +14,7 @@ In diesem Repository finden Sie eine große Auswahl an Algorithmen und Datenstru ## Beteiligen -Sie können sich gerne auch an diesem Projekt beteiligen. Zum Beispiel selbst Algorithmen und Datenstrukturen beisteuern, oder bereits bestehende Implementierungen verbessern, oder auch dokumentieren. Fühlen Sie sich frei und machen Sie einen Pull-Request. Alternativ können Sie auch den Issue-Tracker benutzen um auf Probleme (Bugs) in bereits bestehenden Implementierungen hinzuweisen. +Sie können sich gerne auch an diesem Projekt beteiligen. Zum Beispiel selbst Algorithmen und Datenstrukturen beisteuern, oder bereits bestehende Implementierungen verbessern, oder auch dokumentieren. Fühlen Sie sich frei und machen Sie einen Pull-Request. Alternativ können Sie auch den Issue-Tracker benutzen um auf Probleme (Bugs) in bereits bestehenden Implementierungen hinzuweisen. In diesem Projekt halten wir uns an die [PEP8](https://www.python.org/dev/peps/pep-0008/) Codestyle Konventionen. diff --git a/README_JP.md b/README_JP.md index 1fea3b826..7e3062e1d 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,6 +1,6 @@

-[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_KR.md b/README_KR.md index 52c7da65f..91bfc0a38 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,6 +1,6 @@

-[English](README.md) | [Brazilian Portuguese](README_PTBR.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) @@ -15,7 +15,6 @@ Python 3로 구현한 간단하고 명확한 자료구조와 알고리즘들의 ## 기여 활동 프로젝트 활동 참여에 관심을 가져주셔서 감사합니다! 여러가지 방법으로 이 프로젝트에 기여해주세요. [기여 방법 소개](CONTRIBUTING.md) - ## 테스트 종류들 ### unittest 사용 diff --git a/README_PTBR.md b/README_PTBR.md index 6a4973af3..2a9e05fba 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -1,6 +1,6 @@

-[English](README.md) | Brazilian Portuguese | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) @@ -15,7 +15,6 @@ Exemplos de implementações mínimas e limpas de estruturas de dados e algoritm ## Contribuir Obrigado pelo seu interesse em contribuir! Há muitas maneiras de contribuir para este projeto. [Comece aqui](CONTRIBUTING.md) - ## Testes ### Usando unittest From 77e8af74c58d0d0ba20507b49bd3e6f58de84dcb Mon Sep 17 00:00:00 2001 From: LJX <335272236@qq.com> Date: Tue, 10 Jul 2018 21:11:44 +0800 Subject: [PATCH 089/302] added text_justification with tests (#371) * add text_justification and test text_justification * add text_justification and test text_justification --- algorithms/strings/__init__.py | 1 + algorithms/strings/text_justification.py | 89 ++++++++++++++++++++++++ tests/test_strings.py | 65 ++++++++++++++--- 3 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 algorithms/strings/text_justification.py diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 4040c9e85..4f4f20c7a 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -28,3 +28,4 @@ from .contain_string import * from .count_binary_substring import * from .repeat_string import * +from .text_justification import * \ No newline at end of file diff --git a/algorithms/strings/text_justification.py b/algorithms/strings/text_justification.py new file mode 100644 index 000000000..a14a8ba39 --- /dev/null +++ b/algorithms/strings/text_justification.py @@ -0,0 +1,89 @@ +""" +Given an array of words and a width maxWidth, format the text such that each line +has exactly maxWidth characters and is fully (left and right) justified. + +You should pack your words in a greedy approach; that is, pack as many words as +you can in each line. Pad extra spaces ' ' when necessary so that each line has +exactly maxWidth characters. + +Extra spaces between words should be distributed as evenly as possible. If the +number of spaces on a line do not divide evenly between words, the empty slots +on the left will be assigned more spaces than the slots on the right. + +For the last line of text, it should be left justified and no extra space is +inserted between words. + +Note: +A word is defined as a character sequence consisting of non-space characters only. +Each word's length is guaranteed to be greater than 0 and not exceed maxWidth. +The input array words contains at least one word. + +Example: +Input: +words = ["What","must","be","acknowledgment","shall","be"] +maxWidth = 16 +Output: +[ + "What must be", + "acknowledgment ", + "shall be " +] +""" + + +def text_justification(words, max_width): + ''' + :type words: list + :type max_width: int + :rtype: list + ''' + ret = [] # return value + row_len = 0 # current length of strs in a row + row_words = [] # current words in a row + index = 0 # the index of current word in words + is_first_word = True # is current word the first in a row + while index < len(words): + while row_len <= max_width and index < len(words): + if len(words[index]) > max_width: + raise ValueError("there exists word whose length is larger than max_width") + tmp = row_len + row_words.append(words[index]) + tmp += len(words[index]) + if not is_first_word: + tmp += 1 # except for the first word, each word should have at least a ' ' before it. + if tmp > max_width: + row_words.pop() + break + row_len = tmp + index += 1 + is_first_word = False + # here we have already got a row of str , then we should supplement enough ' ' to make sure the length is max_width. + row = "" + # if the row is the last + if index == len(words): + for word in row_words: + row += (word + ' ') + row = row[:-1] + row += ' ' * (max_width - len(row)) + # not the last row and more than one word + elif len(row_words) != 1: + space_num = max_width - row_len + space_num_of_each_interval = space_num // (len(row_words) - 1) + space_num_rest = space_num - space_num_of_each_interval * (len(row_words) - 1) + for j in range(len(row_words)): + row += row_words[j] + if j != len(row_words) - 1: + row += ' ' * (1 + space_num_of_each_interval) + if space_num_rest > 0: + row += ' ' + space_num_rest -= 1 + # row with only one word + else: + row += row_words[0] + row += ' ' * (max_width - len(row)) + ret.append(row) + # after a row , reset those value + row_len = 0 + row_words = [] + is_first_word = True + return ret diff --git a/tests/test_strings.py b/tests/test_strings.py index c8b918280..be44fb93c 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -30,7 +30,8 @@ caesar_cipher, contain_string, count_binary_substring, - repeat_string + repeat_string, + text_justification ) import unittest @@ -62,10 +63,13 @@ def setUp(self): self.words = ['Amazon', 'Microsoft', 'Google'] self.symbols = ['i', 'Am', 'cro', 'le', 'abc'] self.result = ['M[i]crosoft', '[Am]azon', 'Mi[cro]soft', 'Goog[le]'] + def test_match_symbol(self): - self.assertEqual(self.result, match_symbol(self.words,self.symbols)) + self.assertEqual(self.result, match_symbol(self.words, self.symbols)) + def test_match_symbol_1(self): - self.assertEqual(['[Am]azon', 'Mi[cro]soft', 'Goog[le]'], match_symbol_1(self.words,self.symbols)) + self.assertEqual(['[Am]azon', 'Mi[cro]soft', 'Goog[le]'], match_symbol_1(self.words, self.symbols)) + def test_bracket(self): self.assertEqual(('[Am]azon', 'Mi[cro]soft', 'Goog[le]'), bracket(self.words, self.symbols)) @@ -105,6 +109,7 @@ class TestDomainExtractor(unittest.TestCase): def test_valid(self): self.assertEqual(domain_name_1("https://github.com/SaadBenn"), "github") + def test_invalid(self): self.assertEqual(domain_name_2("http://google.com"), "google") @@ -119,6 +124,7 @@ class TestEncodeDecode(unittest.TestCase): def test_encode(self): self.assertEqual("4:keon2:is7:awesome", encode("keon is awesome")) + def test_decode(self): self.assertEqual(['keon', 'is', 'awesome'], decode("4:keon2:is7:awesome")) @@ -133,7 +139,7 @@ class TestGroupAnagrams(unittest.TestCase): def test_group_anagrams(self): self.assertEqual([['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']], \ - group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"])) + group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"])) class TestIntToRoman(unittest.TestCase): @@ -162,14 +168,17 @@ def test_is_palindrome(self): # 'Otto' is a old german name. self.assertTrue(is_palindrome("Otto")) self.assertFalse(is_palindrome("house")) + def test_is_palindrome_reverse(self): # 'Otto' is a old german name. self.assertTrue(is_palindrome_reverse("Otto")) self.assertFalse(is_palindrome_reverse("house")) + def test_is_palindrome_two_pointer(self): # 'Otto' is a old german name. self.assertTrue(is_palindrome_two_pointer("Otto")) self.assertFalse(is_palindrome_two_pointer("house")) + def test_is_palindrome_stack(self): # 'Otto' is a old german name. self.assertTrue(is_palindrome_stack("Otto")) @@ -232,6 +241,7 @@ class TestMergeStringChecker(unittest.TestCase): def test_is_merge_recursive(self): self.assertTrue(is_merge_recursive("codewars", "cdw", "oears")) + def test_is_merge_iterative(self): self.assertTrue(is_merge_iterative("codewars", "cdw", "oears")) @@ -263,6 +273,7 @@ def test_is_one_edit(self): self.assertTrue(is_one_edit("abc", "abd")) self.assertFalse(is_one_edit("abc", "aed")) self.assertFalse(is_one_edit("abcd", "abcd")) + def test_is_one_edit2(self): self.assertTrue(is_one_edit2("abc", "abd")) self.assertFalse(is_one_edit2("abc", "aed")) @@ -292,10 +303,13 @@ class TestReverseString(unittest.TestCase): def test_recursive(self): self.assertEqual("ereht olleh", recursive("hello there")) + def test_iterative(self): self.assertEqual("ereht olleh", iterative("hello there")) + def test_pythonic(self): self.assertEqual("ereht olleh", pythonic("hello there")) + def test_ultra_pythonic(self): self.assertEqual("ereht olleh", ultra_pythonic("hello there")) @@ -322,7 +336,7 @@ class TestReverseWords(unittest.TestCase): def test_reverse_words(self): self.assertEqual("pizza like I and kim keon am I", \ - reverse_words("I am keon kim and I like pizza")) + reverse_words("I am keon kim and I like pizza")) class TestRomanToInt(unittest.TestCase): @@ -367,11 +381,12 @@ class TestValidateCoordinates(unittest.TestCase): """ def test_valid(self): - valid_coordinates = ["-23, 25","4, -3","90, 180","-90, -180"] + valid_coordinates = ["-23, 25", "4, -3", "90, 180", "-90, -180"] for coordinate in valid_coordinates: self.assertTrue(is_valid_coordinates_0(coordinate)) + def test_invalid(self): - invalid_coordinates = ["23.234, - 23.4234","99.234, 12.324","6.325624, 43.34345.345","0, 1,2","23.245, 1e1"] + invalid_coordinates = ["23.234, - 23.4234", "99.234, 12.324", "6.325624, 43.34345.345", "0, 1,2", "23.245, 1e1"] for coordinate in invalid_coordinates: self.assertFalse(is_valid_coordinates_0(coordinate)) @@ -386,46 +401,74 @@ class TestWordSquares(unittest.TestCase): def test_word_squares(self): self.assertEqual([['wall', 'area', 'lead', 'lady'], ['ball', 'area', 'lead', 'lady']], \ - word_squares(["area","lead","wall","lady","ball"])) + word_squares(["area", "lead", "wall", "lady", "ball"])) + class TestUniqueMorse(unittest.TestCase): def test_convert_morse_word(self): self.assertEqual("--...-.", convert_morse_word("gin")) self.assertEqual("--...--.", convert_morse_word("msg")) + def test_unique_morse(self): self.assertEqual(2, unique_morse(["gin", "zen", "gig", "msg"])) + class TestJudgeCircle(unittest.TestCase): def test_judge_circle(self): self.assertTrue(judge_circle("UDLRUD")) self.assertFalse(judge_circle("LLRU")) + class TestStrongPassword(unittest.TestCase): def test_strong_password(self): - self.assertEqual(3, strong_password(3,"Ab1")) - self.assertEqual(1, strong_password(11,"#Algorithms")) + self.assertEqual(3, strong_password(3, "Ab1")) + self.assertEqual(1, strong_password(11, "#Algorithms")) + class TestCaesarCipher(unittest.TestCase): def test_caesar_cipher(self): self.assertEqual("Lipps_Asvph!", caesar_cipher("Hello_World!", 4)) self.assertEqual("okffng-Qwvb", caesar_cipher("middle-Outz", 2)) + class TestContainString(unittest.TestCase): def test_contain_string(self): self.assertEqual(-1, contain_string("mississippi", "issipi")) self.assertEqual(0, contain_string("Hello World", "")) self.assertEqual(2, contain_string("hello", "ll")) + class TestCountBinarySubstring(unittest.TestCase): def test_count_binary_substring(self): self.assertEqual(6, count_binary_substring("00110011")) self.assertEqual(4, count_binary_substring("10101")) self.assertEqual(3, count_binary_substring("00110")) + class TestCountBinarySubstring(unittest.TestCase): def test_repeat_string(self): - self.assertEqual(3, repeat_string("abcd","cdabcdab")) + self.assertEqual(3, repeat_string("abcd", "cdabcdab")) self.assertEqual(4, repeat_string("bb", "bbbbbbb")) + +class TestTextJustification(unittest.TestCase): + def test_text_justification(self): + self.assertEqual(["This is an", + "example of text", + "justification. "], + + text_justification(["This", "is", "an", "example", "of", "text", "justification."] + , 16) + ) + + self.assertEqual(["What must be", + "acknowledgment ", + "shall be "], + + text_justification(["What", "must", "be", "acknowledgment", "shall", "be"] + , 16) + ) + + if __name__ == "__main__": unittest.main() From 77054e71123a7d65485a92c85a990301475e8152 Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Wed, 18 Jul 2018 02:31:03 -0700 Subject: [PATCH 090/302] PR to add some problem. (#375) * Add next_greatest_letter to search * Move top sort test into test_sort * Add min_distance to string * Add binary_gap to bit --- README.md | 3 ++ algorithms/bit/__init__.py | 1 + algorithms/bit/binary_gap.py | 27 ++++++++++ algorithms/search/__init__.py | 1 + algorithms/search/next_greatest_letter.py | 60 +++++++++++++++++++++++ algorithms/strings/__init__.py | 3 +- algorithms/strings/min_distance.py | 28 +++++++++++ tests/graph/__init__.py | 1 - tests/graph/test_topsort.py | 27 ---------- tests/test_bit.py | 13 ++++- tests/test_search.py | 24 +++++++-- tests/test_sort.py | 34 ++++++++++--- tests/test_strings.py | 8 ++- 13 files changed, 189 insertions(+), 41 deletions(-) create mode 100644 algorithms/bit/binary_gap.py create mode 100644 algorithms/search/next_greatest_letter.py create mode 100644 algorithms/strings/min_distance.py delete mode 100644 tests/graph/__init__.py delete mode 100644 tests/graph/test_topsort.py diff --git a/README.md b/README.md index 8a0ef8e61..d918575e2 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ If you want to uninstall algorithms, it is as simple as: - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - [insert_bit](algorithms/bit/insert_bit.py) - [remove_bit](algorithms/bit/remove_bit.py) + - [binary_gap](algorithms/bit/binary_gap.py) - [calculator](algorithms/calculator) - [math_parser](algorithms/calculator/math_parser.py) - [dfs](algorithms/dfs) @@ -226,6 +227,7 @@ If you want to uninstall algorithms, it is as simple as: - [find_min_rotate](algorithms/search/find_min_rotate.py) - [search_rotate](algorithms/search/search_rotate.py) - [jump_search](algorithms/search/jump_search.py) + - [next_greatest_letter](algorithms/search/next_greatest_letter.py) - [set](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) @@ -292,6 +294,7 @@ If you want to uninstall algorithms, it is as simple as: - [contain_string](algorithms/strings/contain_string.py) - [count_binary_substring](algorithms/strings/count_binary_substring.py) - [repeat_string](algorithms/strings/repeat_string.py) + - [min_distance](algorithms/strings/min_distance.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/algorithms/bit/__init__.py b/algorithms/bit/__init__.py index 383923d46..617f5006f 100644 --- a/algorithms/bit/__init__.py +++ b/algorithms/bit/__init__.py @@ -15,3 +15,4 @@ from .remove_bit import * from .count_flips_to_convert import * from .flip_bit_longest_sequence import * +from .binary_gap import * diff --git a/algorithms/bit/binary_gap.py b/algorithms/bit/binary_gap.py new file mode 100644 index 000000000..75a1233b5 --- /dev/null +++ b/algorithms/bit/binary_gap.py @@ -0,0 +1,27 @@ +""" +Given a positive integer N, find and return the longest distance between two +consecutive 1' in the binary representation of N. +If there are not two consecutive 1's, return 0 + +For example: +Input: 22 +Output: 2 +Explanation: +22 in binary is 10110 +In the binary representation of 22, there are three ones, and two consecutive pairs of 1's. +The first consecutive pair of 1's have distance 2. +The second consecutive pair of 1's have distance 1. +The answer is the largest of these two distances, which is 2 +""" +def binary_gap(N): + last = None + ans = 0 + index = 0 + while N != 0: + if N & 1: + if last is not None: + ans = max(ans, index - last) + last = index + index = index + 1 + N = N >> 1 + return ans diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index 8304059e9..ac5220b38 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -8,3 +8,4 @@ from .find_min_rotate import * from .search_rotate import * from .jump_search import * +from .next_greatest_letter import * diff --git a/algorithms/search/next_greatest_letter.py b/algorithms/search/next_greatest_letter.py new file mode 100644 index 000000000..5abe001cd --- /dev/null +++ b/algorithms/search/next_greatest_letter.py @@ -0,0 +1,60 @@ +''' +Given a list of sorted characters letters containing only lowercase letters, +and given a target letter target, find the smallest element in the list that +is larger than the given target. + +Letters also wrap around. For example, if the target is target = 'z' and +letters = ['a', 'b'], the answer is 'a'. + +Input: +letters = ["c", "f", "j"] +target = "a" +Output: "c" + +Input: +letters = ["c", "f", "j"] +target = "c" +Output: "f" + +Input: +letters = ["c", "f", "j"] +target = "d" +Output: "f" + +Reference: https://leetcode.com/problems/find-smallest-letter-greater-than-target/description/ +''' + +import bisect + +""" +Using bisect libarary +""" +def next_greatest_letter(letters, target): + index = bisect.bisect(letters, target) + return letters[index % len(letters)] + +""" +Using binary search: complexity O(logN) +""" +def next_greatest_letter_v1(letters, target): + if letters[0] > target: + return letters[0] + if letters[len(letters) - 1] <= target: + return letters[0] + left, right = 0, len(letters) - 1 + while left <= right: + mid = left + (right - left) // 2 + if letters[mid] > target: + right = mid - 1 + else: + left = mid + 1 + return letters[left] + +""" +Brute force: complexity O(N) +""" +def next_greatest_letter_v2(letters, target): + for index in letters: + if index > target: + return index + return letters[0] diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 4f4f20c7a..d7ae4b673 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -28,4 +28,5 @@ from .contain_string import * from .count_binary_substring import * from .repeat_string import * -from .text_justification import * \ No newline at end of file +from .text_justification import * +from .min_distance import * diff --git a/algorithms/strings/min_distance.py b/algorithms/strings/min_distance.py new file mode 100644 index 000000000..4e80f471f --- /dev/null +++ b/algorithms/strings/min_distance.py @@ -0,0 +1,28 @@ +""" +Given two words word1 and word2, find the minimum number of steps required to +make word1 and word2 the same, where in each step you can delete one character +in either string. + +For example: +Input: "sea", "eat" +Output: 2 +Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea". + +Reference: https://leetcode.com/problems/delete-operation-for-two-strings/description/ +""" + +def min_distance(word1, word2): + return len(word1) + len(word2) - 2 * lcs(word1, word2, len(word1), len(word2)) + +def lcs(s1, s2, i, j): + """ + The length of longest common subsequence among the two given strings s1 and s2 + """ + if i == 0 or j == 0: + return 0 + elif s1[i - 1] == s2[j - 1]: + return 1 + lcs(s1, s2, i - 1, j - 1) + else: + return max(lcs(s1, s2, i - 1, j), lcs(s1, s2, i, j - 1)) + +# TODO: Using dynamic programming diff --git a/tests/graph/__init__.py b/tests/graph/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/tests/graph/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/graph/test_topsort.py b/tests/graph/test_topsort.py deleted file mode 100644 index a308ed306..000000000 --- a/tests/graph/test_topsort.py +++ /dev/null @@ -1,27 +0,0 @@ -from algorithms.sort import ( - top_sort, top_sort_recursive -) - -import unittest - -class TestSuite(unittest.TestCase): - def setUp(self): - self.depGraph = { - "a" : [ "b" ], - "b" : [ "c" ], - "c" : [ 'e'], - 'e' : [ 'g' ], - "d" : [ ], - "f" : ["e" , "d"], - "g" : [ ] - } - - def test_topsort(self): - res = top_sort_recursive(self.depGraph) - #print(res) - self.assertTrue(res.index('g') < res.index('e')) - res = top_sort(self.depGraph) - self.assertTrue(res.index('g') < res.index('e')) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_bit.py b/tests/test_bit.py index fdc80a18e..acfb4b035 100644 --- a/tests/test_bit.py +++ b/tests/test_bit.py @@ -15,7 +15,8 @@ find_difference, has_alternative_bit, has_alternative_bit_fast, insert_one_bit, insert_mult_bits, - remove_bit + remove_bit, + binary_gap ) import unittest @@ -238,6 +239,16 @@ def test_remove_bit(self): self.assertEqual(5, remove_bit(21, 4)) self.assertEqual(10, remove_bit(21, 0)) + def test_binary_gap(self): + # 22 = 10110 + self.assertEqual(2, binary_gap(22)) + # 6 = 110 + self.assertEqual(1, binary_gap(6)) + # 8 = 1000 + self.assertEqual(0, binary_gap(8)) + # 145 = 10010001 + self.assertEqual(4, binary_gap(145)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_search.py b/tests/test_search.py index 4f869fe18..60d8919f7 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -8,7 +8,8 @@ search_range, find_min_rotate, find_min_rotate_recur, search_rotate, search_rotate_recur, - jump_search + jump_search, + next_greatest_letter, next_greatest_letter_v1, next_greatest_letter_v2 ) import unittest @@ -46,7 +47,7 @@ def test_last_occurrence(self): self.assertEqual(None, last_occurrence(array, 7)) self.assertEqual(0, last_occurrence(array, 1)) self.assertEqual(13, last_occurrence(array, 6)) - + def test_linear_search(self): array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6, 6, 6] self.assertEqual(6, linear_search(array, 4)) @@ -103,7 +104,24 @@ def test_jump_search(self): self.assertEqual(2, jump_search(array, 3)) self.assertEqual(-1, jump_search(array, 7)) self.assertEqual(-1, jump_search(array, -1)) - + + def test_next_greatest_letter(self): + letters = ["c", "f", "j"] + target = "a" + self.assertEqual("c", next_greatest_letter(letters, target)) + self.assertEqual("c", next_greatest_letter_v1(letters, target)) + self.assertEqual("c", next_greatest_letter_v2(letters, target)) + letters = ["c", "f", "j"] + target = "d" + self.assertEqual("f", next_greatest_letter(letters, target)) + self.assertEqual("f", next_greatest_letter_v1(letters, target)) + self.assertEqual("f", next_greatest_letter_v2(letters, target)) + letters = ["c", "f", "j"] + target = "j" + self.assertEqual("c", next_greatest_letter(letters, target)) + self.assertEqual("c", next_greatest_letter_v1(letters, target)) + self.assertEqual("c", next_greatest_letter_v2(letters, target)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_sort.py b/tests/test_sort.py index d77f086d9..650f33920 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -16,6 +16,7 @@ radix_sort, gnome_sort, cocktail_shaker_sort, + top_sort, top_sort_recursive ) import unittest @@ -25,15 +26,15 @@ class TestSuite(unittest.TestCase): def test_bogo_sort(self): self.assertEqual([1, 5, 23], bogo_sort([1, 23, 5])) - + def test_bitonic_sort(self): self.assertEqual([1, 2, 3, 5, 23, 57, 65, 1232], bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232])) self.assertEqual([1, 2, 3, 5, 23, 57, 65, 1232], bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232],False)) self.assertEqual([1232, 65, 57, 23, 5, 3, 2, 1], - bitonic_sort([1, 2, 3, 5, 65, 23, 57, 1232],True)) - + bitonic_sort([1, 2, 3, 5, 65, 23, 57, 1232],True)) + def test_bubble_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], bubble_sort([1, 5, 65, 23, 57, 1232])) @@ -69,7 +70,7 @@ def test_merge_sort(self): def test_pancake_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], pancake_sort([1, 5, 65, 23, 57, 1232])) - + def test_quick_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], quick_sort([1, 5, 65, 23, 57, 1232])) @@ -85,19 +86,38 @@ def test_bucket_sort(self): def test_shell_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], shell_sort([1, 5, 65, 23, 57, 1232])) - + def test_radix_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], radix_sort([1, 5, 65, 23, 57, 1232])) - + def test_gnome_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], gnome_sort([1, 5, 65, 23, 57, 1232])) - + def test_cocktail_shaker_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], cocktail_shaker_sort([1, 5, 65, 23, 57, 1232])) +class TestTopSort(unittest.TestCase): + def setUp(self): + self.depGraph = { + "a" : [ "b" ], + "b" : [ "c" ], + "c" : [ 'e'], + 'e' : [ 'g' ], + "d" : [ ], + "f" : ["e" , "d"], + "g" : [ ] + } + + def test_topsort(self): + res = top_sort_recursive(self.depGraph) + #print(res) + self.assertTrue(res.index('g') < res.index('e')) + res = top_sort(self.depGraph) + self.assertTrue(res.index('g') < res.index('e')) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_strings.py b/tests/test_strings.py index be44fb93c..0c77ac12a 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -31,7 +31,8 @@ contain_string, count_binary_substring, repeat_string, - text_justification + text_justification, + min_distance ) import unittest @@ -469,6 +470,11 @@ def test_text_justification(self): , 16) ) +class TestMinDistance(unittest.TestCase): + def test_min_distance(self): + self.assertEqual(2, min_distance("sea", "eat")) + self.assertEqual(6, min_distance("abAlgocrithmf", "Algorithmmd")) + if __name__ == "__main__": unittest.main() From 73918832b93840b452c9db34446b7382de83e912 Mon Sep 17 00:00:00 2001 From: "Jibbie R. Eguna" <35353768+jbeguna04@users.noreply.github.com> Date: Thu, 19 Jul 2018 01:48:08 +0800 Subject: [PATCH 091/302] Logo Designs (#376) * Create add * Add files via upload * Update README.md * Update README.md * Update README.md --- LogoDesins/128pxblack.png | Bin 0 -> 1317 bytes LogoDesins/128pxblack.svg | 10 +++++++++ LogoDesins/128pxblue.png | Bin 0 -> 1600 bytes LogoDesins/128pxblue.svg | 13 +++++++++++ LogoDesins/128pxorange.png | Bin 0 -> 1603 bytes LogoDesins/128pxorange.svg | 13 +++++++++++ LogoDesins/256pxblack.png | Bin 0 -> 3194 bytes LogoDesins/256pxblack.svg | 10 +++++++++ LogoDesins/256pxblue.png | Bin 0 -> 3233 bytes LogoDesins/256pxblue.svg | 13 +++++++++++ LogoDesins/256pxorange.png | Bin 0 -> 3234 bytes LogoDesins/256pxorange.svg | 13 +++++++++++ LogoDesins/512pxblack.png | Bin 0 -> 6779 bytes LogoDesins/512pxblack.svg | 10 +++++++++ LogoDesins/512pxblue.png | Bin 0 -> 6605 bytes LogoDesins/512pxblue.svg | 13 +++++++++++ LogoDesins/512pxorange.png | Bin 0 -> 6582 bytes LogoDesins/512pxorange.svg | 13 +++++++++++ LogoDesins/add | 1 + LogoDesins/logotype1black.png | Bin 0 -> 7616 bytes LogoDesins/logotype1black.svg | 33 ++++++++++++++++++++++++++++ LogoDesins/logotype1blue.png | Bin 0 -> 7535 bytes LogoDesins/logotype1blue.svg | 38 +++++++++++++++++++++++++++++++++ LogoDesins/logotype1orange.png | Bin 0 -> 7509 bytes LogoDesins/logotype1orange.svg | 38 +++++++++++++++++++++++++++++++++ LogoDesins/logotype2black.png | Bin 0 -> 4357 bytes LogoDesins/logotype2black.svg | 32 +++++++++++++++++++++++++++ LogoDesins/logotype2blue.png | Bin 0 -> 4403 bytes LogoDesins/logotype2blue.svg | 35 ++++++++++++++++++++++++++++++ LogoDesins/logotype2orange.png | Bin 0 -> 4368 bytes LogoDesins/logotype2orange.svg | 35 ++++++++++++++++++++++++++++++ README.md | 2 +- 32 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 LogoDesins/128pxblack.png create mode 100644 LogoDesins/128pxblack.svg create mode 100644 LogoDesins/128pxblue.png create mode 100644 LogoDesins/128pxblue.svg create mode 100644 LogoDesins/128pxorange.png create mode 100644 LogoDesins/128pxorange.svg create mode 100644 LogoDesins/256pxblack.png create mode 100644 LogoDesins/256pxblack.svg create mode 100644 LogoDesins/256pxblue.png create mode 100644 LogoDesins/256pxblue.svg create mode 100644 LogoDesins/256pxorange.png create mode 100644 LogoDesins/256pxorange.svg create mode 100644 LogoDesins/512pxblack.png create mode 100644 LogoDesins/512pxblack.svg create mode 100644 LogoDesins/512pxblue.png create mode 100644 LogoDesins/512pxblue.svg create mode 100644 LogoDesins/512pxorange.png create mode 100644 LogoDesins/512pxorange.svg create mode 100644 LogoDesins/add create mode 100644 LogoDesins/logotype1black.png create mode 100644 LogoDesins/logotype1black.svg create mode 100644 LogoDesins/logotype1blue.png create mode 100644 LogoDesins/logotype1blue.svg create mode 100644 LogoDesins/logotype1orange.png create mode 100644 LogoDesins/logotype1orange.svg create mode 100644 LogoDesins/logotype2black.png create mode 100644 LogoDesins/logotype2black.svg create mode 100644 LogoDesins/logotype2blue.png create mode 100644 LogoDesins/logotype2blue.svg create mode 100644 LogoDesins/logotype2orange.png create mode 100644 LogoDesins/logotype2orange.svg diff --git a/LogoDesins/128pxblack.png b/LogoDesins/128pxblack.png new file mode 100644 index 0000000000000000000000000000000000000000..d18f07fd4467dc3e6c5e8165824757b8feaf7a82 GIT binary patch literal 1317 zcmV+=1={+FP)~oNIC$DP)=*BWb_|yM7IzU~TT~|F| z1`BK>1k^V#=X70Qd&Rd4|C%b*Qb`7_+;oES+LZliqu}Y=0L!k6$v%HkGM_8EZu3yz z$U4KuL>f>X8kH=@8o1RJ9Mp{Kwquz61H5z2mCm`A1m>J;oO1>62k;}t2ZUUB3%(Ad zWL>PhG+${^va%RJzqUa^U08T~j)nZsW@xOG8Q9oxsJyoDc6PJTLn~73d_>v}8huBV zUGdI6jG>_30Eo!KyWXG9xh-Zd?2Z5VD|TxQ$rVrrsM}_Sz(5%&17)BLlz}ocPzK6C z8K{@$19Ss*1yCU(4e+0cR3b7rP$zegi0puGz=QwwUqB-w8v}KKRC3smcsldvx4>r+ zX+)%Wm7tE??4t*A%^rYnBC^Y=U$ex3=4afjuRVGFDs$-9EFq)~hh3bfk#F_U>(~0O zKzTRY1D|`iSzmh#d=Zg-D*c*8cC)Q_v&Tpu^XT ziK|4)X3^wkeeD7GDk8OrEY-N4fBK|!v%dBo_}A;#Je%t=jbfn}$+g7DxVw{Lp;P@D zo_lbkn^ghlLpk&-o<@ntQbcOtOJqntIixk}GevIpT&+pm#MR*G(<{>Ca9^DFpr`z{ zOr3^2D7~8e1>I$?!kn5LQyU4FxH=qE!dv`mc%gXyR*s2(vQ{y0NL+313DnJQHsD~K zcFLeeyP2XRPRdvdcb_<JL)Hg9QDFEw^tBt zY`r^v(zF!(w-@WJve2w`&XvHs5b@&}P~U;yoO2t^dFo!jR$jk;@S^@!3l3eEs3jtUC0xt_W+3XT9Rj>_ZSk9xDfiDW7cRVI9HXS5v7V9m9Z zG#iVS!FAFzm`mBX|9#F>EY$;(E3ekyR)@wL#<6Kt+i$3 zW~n9CEOin!zSC&GYYm;PMR=N~^Q5csoo>_l#5KOjn~kMtu9a%iSP`+=*i>tLlN=Y2 z98{zuO?m~?lLHlSIcLxk&E!Ch42QO4YI>-l-(8<&l$y-jV48Y$RwV9mJULJomUBuJ b^%ngfteuPn5 + + + + diff --git a/LogoDesins/128pxblue.png b/LogoDesins/128pxblue.png new file mode 100644 index 0000000000000000000000000000000000000000..b94a8ca38845e00e3b78595e9da2f4401ce0395e GIT binary patch literal 1600 zcmV-G2EX}qd zbx%-r)YRkzbvA8vPVnR##0StXZ!r9-IFciYBt$#F(xHwmeN}C8k z0^kb348Xj|(x(uf?IZ+HN}DqPF@P^S|Fr@T7g?ITdr(T78-g_4^Rfp5ws?1-ls01k za{!ku{_F>Un?BT$9TeH2Ie-rx-(pR+D?Un4WQT45+&X&86|JtjqXDI~nbIm6dU*Q> z0MjB%^MeINb||Lp-nV=sga33epvVrz0Ir#B?wVlDg9oLwiOCiX(Vsk${aOSEN@+78 zJ9Lh47JBr7_n*K#`?+k)>k*A88f)Ur`o`H|KdEixn2bU0!VV0#xY$ zpzQ~E%Pd;LIwN23+L`K+3%?|nepvQ*0Q^P&uB!YY3Oj;=RPw*3F2bRc!QY?i5^t4< zjr1#x0OY<;K0K_jDS+=*sz*9~yD#2322t8{$yClxOU8Rb{!RjsSF-iYp8$+QDX|F_ zlmL2L27*992`B+2pahhF5)n`WN1h66rOkZzr1sr|QrbjHn>zr% z@aI7D3wBOw-!&*o7FJct0Go95SEWr}I==5sPWw_bG(QqQ2k=X2kljgO zS0rY2sM<9ZJYa-$gUvC$Z6)0;*{|tQt*DOeW=*B_fveTwf=4xTarn4TF3EmbmlE}| z>y^}us~6@Pn>x(cm;W_zt!7G_C4jHsuR(8IxZ0b0z@%nPWl;<+!PMLrJ8oFOp z+_|1~u}@kLb?Dit-GE|T;?`qAdTRFmKOgmz0n&_&wbd+@B1@N4c>ft53h!C72Ni1O zyo-TqO-J+ttXX!wj>#BlsP0;w=^IM9o^PuDn!u|LEg0PCckuZ#C+a5+3;o zwOp;JHU9ME^m+Fx)0e#^&ZJ-47wGBoZ5+PAF|Dgx;vzPnIcOU zMV3Y(`%yUqt zY7***bdWZDqH)h>+7ZEEzwmk*$=gEnQx1S>wO-eQC3e9rAlw zYK8p@WpGVXHRHX0modf)CgzkY!nr|t$^&(ka4(&&a3|s(?3cI8#=K5VWOf?A5hO3U zFP4F&p2MNmQ#pbKwPU|rrE}QE1+aqJv0panoK7j4g9Bw54prXychsO-rcs>TaeT0# yO7<(p>vYbF0404tV-TQr>{mkJ5Zh5#6ZsFGLt6qw_m$oN0000 + + + + + diff --git a/LogoDesins/128pxorange.png b/LogoDesins/128pxorange.png new file mode 100644 index 0000000000000000000000000000000000000000..683883494da11607113900b5c8fde81e92f4b95e GIT binary patch literal 1603 zcmV-J2E6%+P)H$JNaYYWIkslZAFaR;U< zh_-?-6~tx(kt>M2bK_;H4y+2i2SFQJCMA+H1CC_il0#&P`ZT}*7yxtf^74XE#Ap=( zNC8{}m;#u^S^gZtvz>$h%4l^CAOY}Y>%W!&k~quLcMr;FbxV*2J6`rkz~=7`l+kJg zU9+sRufu90}pTi z2w)Otd2z6y$POj6-TRim$>2X93@EZg34j}Bo4X=dv*1A)trD_D1N0|PWWVOYfihZ+ z$qrp09C;vMMem@DRzm`Gjc~;}9O?{eN7xantY~$mY@iy39id96aHth1+V0c9>`+(v zPQVIhpd5r9ZB=B>_*t_i_Up8vv0hX>_!Pijw6nN$8lyPN$MoKhoA~8b8Or6;=0u#TLwSi@^3%oaLjchXVlGr6O9vzU3Og zFQZjT->WgGy5%?_!;X%--wMDq&hn^9^dD#WGo@879jkhs+yE$Oci*jgWSf5Vz1sw^ z`z`^D&vv}v+=Ko*N$1jgL`?qN1%UA`)hitSBA>|)&0T&2$`VAhTY8m!yWX?quf=xc zv~|?wJXYLi%)6#p9{^m&S)Onm1jJch#92N9@QGHj{}pACcypcyvRGjW+~viluRxU! z0NQ?lx6Gm?taI`OZ=9(fx$p~e=?7(h2f!cn@3P7tqOc<NzS|Y=9D^9Gx@0P+XC>o3CVwY|$Q#*s=Fb2|p_JGJ z3rYa(ms3F?pahhF5>Nt4K#2$_0VSXWRAqD@38>wGMszg)uhD9@eNy}GK^d(gqt!it zpZI;C`2|}iweK1fB@3%6Wq@@$`m52ZC>`JTCTD%A8JZu7UjX=Nv~pIs+C^AJ zuqzU?I#lhN3O;3obc^*dy=^7k9oetRQLU(s?Pg7-^?|F^;etmsb8+~%ORmU%S(g&^ zvg?)9jH?&s2J1S^#Fzhd>RQc=Rto@M!C!;kxNx;M_kc;wn#u)$A4V&u2f3#XAWfLn ztf|x%uCjtMS`Cd>bF9zuLvHoh6s{($?!f^z3zcPwZUwUK+ymy~cwhF*pD}0b$>Z#U zac859R_8{m8P@gYz9BsT7*gxVCH(inxUo^>i=+%{Ry)5Sp!VD88&IChkUM1p0%+)d zRdMHf(#0-mJ=CFRr*;jBafw@x3F)cX`~Q5@4+cn6GS*hJRN^dOP~rV&cqqJQ%^p;! zne#3Nsx=+b53pj{^*ScAysKFYb&TM5#EG|5uoE?FvAT*<;r)}3&p7j-X1&#@Q%ZQ~ zBh+%WqE`6blh=D8zmGm-7oavR_-RNXhwDCM8`XOvr!nYO5OQkAwtdJpE9(A``eouQ zpT}7qh3rQig$O7CC7=Y9fD%vwN<=^jC;=s)1eAahP$B|KKnW-TC7=Y9h=3AM0!ly~ zH>h!_GYaa&rfbxu_TUQZ83kT1*K!1C1k20DT&P}fGYU$8BBND`^-Kk;;#k+Ei9rli zwwQTbC(cU~H$A@hec7*?na9@Rv)C2j9sKUI{@nZA1Mf2msIe)9=f)-uKWYHro6&0S zdd3R%$P{2```D;n0-hci;6SfCDK`y8;JwJJ^p*+t7OXB|}@;Z7w3@v<(Z!&uU~V + + + + + diff --git a/LogoDesins/256pxblack.png b/LogoDesins/256pxblack.png new file mode 100644 index 0000000000000000000000000000000000000000..4c1f054d5e0f6c2d1283ea1d7c7ba54d8debbda0 GIT binary patch literal 3194 zcma)9dpOf?8~<)*V@y%Vp)5Hc$|)ITn}+F^Ls+7eT6&!}hl)yOO)`nL4sy&$jfoH= zhpZDhv=Fnl-%1AwDJ`jG{k-e_y_ync zq<6Ti>jYaUGxS{Ir<8et1hu?X*dGS0hd^7^=ciZIt1citHHPGx1ka6I;_3-+bLlr{&mi$ildOTH z!Q)82{JAvf6_Fz4i{etf^Ipwhw~9+cW_98*u1TrhQPLZd*PHQ(mXy)Z2P9@KcjF$u|1#r7eH(Oj z%qJK%a{@VG-^TFNIhH=;|4y;L8`owX>14e<7!jt$Z3as9;o<sN1J z^;qr%!AE8xuiy2Zh`+R1iun>GQo|!Q$Ul@m?N3v?Vl*%k$&y)4=~tRP>K=7d>Pk#( zBdd;V9+V%kgF3CQ(})8eF8P?@ozaiPR*fQpmfa@GZstBQ_j3>HFWKk%K z#~~WxT&6HrtE1Ue=#Frxq@}I<0DH5Cm%%AS20~I$7R0ONF&PIzB|f)o0rF&6&~Tb2XN~bIu@x#>3im8>2PFGn?%xsQj^7a)?sr77P_t5? z#YB0ZLNTDLr_>#m$qE2er^-YExkVd!dI7tic_OjE^l>8E#)5DZG1OPM+J9 zq%j_fb4Y!#+LN*Oxlo^{?M{hZ{oxbAxDn|NQ8jkZX5Npx`Elm6AMhs~-z#5fk2h|7 zxbXF;(t*vzjRJBMqYyBE((U*-K z*5UtBa$3P`gc;OaETe={inL77BpcYA8d)xVoq1U;AJS_?*EvLdX}B0;4p2`2NiKwd z706_-#s*i})IDjC2P29Y{+7)W*{(Rhw#Y4pcy#6V_Q=<3G1fnxiH3$D&EO z(`OY{H6gET%k2i@SG_gyA%(}lLxy78H6bedChL=P{AJOvT`-Hz$!CupIk4%8=!)Da zaV2Yzbkpz7cz2efi(u&o6g4NnY_aW%Ea2>D_jHt^*{KZgr$-Stez_PcCYY^LYD)c( za+V=?NOd&nnx)s~pW^FNmx(?(P(%8eGM zc7FrhLEpjS*;Vr$F}FwWxi)D(J@sV|AWZQ5-aQ0nRZp-OP!qS;C62Ubns^}pl%&*@ zTG=f#-ztcrDXH>oFb2i9AG|}v0)G6h#MV=ehdxqE+2!~ zgG-U~$f0gmrI-yVQ~ec#k9;y zv-8bRR>hbatL=TWH(n5o69Dd6>I%UbXolwC`}$v4VzTKsfz9fwLqfeNM=DG+G#l@s zE_$S_*$Zq|ayh>-u1slH4!&EiAeS-~&eIMd?QU;(U=@_*J;j<*4Ghrhm%bf|kyWo` z>Lng`glXqz@GHXqGOBh2x^R^&NoOB67SOFrLyxIl(A~NIv2j)u83?})Vhbfd3I?T-vN>9 z=a=P!Y$vU+91f^L&PtyxD^v8(k_{wO`t(euN~A${%B)U57R4pyI=~6d2=RhY12g)o=ey&8TlmUoHX;Dq)*c667l}8WBIHPo8hRb{2qL1KWMFhh^$( zz9<p!hxj?Ja|?N=^hXcq9v`f|t~1~9Qu}@V)tjwh(Dto?1Z#!dPJ-r& z$2x*Kf$w#k+iTbAAFZk7Z5|bN z-v^1bD@$+NWKh%5W~N|E2*nC)sjL1%fW+TAwGClmv`_8J0YKY* zUk37pSK}C2rqLy`ZRdKu`uW80{<*jNDM=NzSVo>w-=pN5AQB=>oS57a+j8>J_t|{O zLY@hZPP@v~7zohoj&5-gD?k-Q3J?=Y;$sIzMPi8;L08D#y(V=4yDu#&Ho + + + + diff --git a/LogoDesins/256pxblue.png b/LogoDesins/256pxblue.png new file mode 100644 index 0000000000000000000000000000000000000000..464efa3f98721f61ac9009302854f5958dc72699 GIT binary patch literal 3233 zcmaJ^cU05K7XA@xfPnOXfKek5YDA+VAPFJ_Rzip(C4^NeQpAFQ^iUR51P#$FDjn&8 z(1}VBVS^NrNK+vo#UO})%Z4Hbc+q`(&O7Iw_x_mjojY^q&YkmpGjj`%vw=veNdf=> zvBg>u1T7T+ga8RKLC+=MC`izNuV7uT0f3bJk0R7R7Q+Vs=~K2=nA2e+3t8q7YQHEX z-i30*#M|_$E(L2VTo>(6k5Z7VYz-4ts}NKwi3+Z6agK)`vL%1J4pTf`AcUaiddR{DcK5tx3B4lSi6S;M)1hRc!IsDLWY>eTjVvTRPT3dbv`$@Sn@INt#SR)zo$q=rx6YRuQW96G0 z*-;+@4CX*eFk4qo|M%jkKOM%?iA`d*QEZXcr}5yS`JmhBu)wL^NkQOoqC)dvAL+bIxnPWqZ^Z-Jchg17KZ2F`x+rRo@{CS3l?d zGSr%yq@JxV-^S$ql>6x@cUtwBfi-%hHh^aQ`1PpMQBef@$AHq>P#O+x+(b+$%QnQ0 zt~yjC{85v1*uS1sh@zM+5u)Dy3WOm>eIw9r0nUD+@P~;ET{AEf5L=#p@;PU`JWR3D zY-c)AEkTjh#X}p_i6A)_6H6rWN-<*@367ak^f5-i1RQZW%JeHY=XwP+|HwlVGG zl6o?qXroU432^cKX6hRod;0FIHocW-eXcCdaLlsvYpxT6qu{FGC z|8;s0wZnZ8%t2E9(;8J=uaiv6<)m5E10na$3(|F& z7Yw%MPV)zh6)6`N7n@Xe6)bn23rC85E$0vp*Fo53>8CH4SV+!+RC5}t-ipo%4|_ut z{^WEWSI}QCMyMMy2VLt^bDPR1k$8l<0aIO?I_Y!*zZN!lQ|vX3I4;_CC3|mYMxsB6 zd%Ce3N741Txkg>A+}WPcGGD$MkE^5eR@ZY)hV8#?UI*6QKE4OYge|9Qu){8ISz(h` znuA{iCR8u^SeG3kT|%`P-%G6`)89NU-_UB>YFY`#__teVRGgugi7}{hzZ)IaF~=O( z`e@xRYTaXC)BJp!JWK5_Js?$@5c?=2elGR>c>i6EC`+~{#i!^@$V*}yo0}wSH|JSm z2b=8kK+Q+LzF!Qxg)wDiR}3kJbf)l9LXO>ds$O;sTOQzOKRCSuFLG-SRuPl06K^F4 zPlh>)+{%}bKSB8${kK#Ots&IIl>>YuUnK$y0Ee!lF(*?`TR_m(P+$(?-4?AZ1cT zlOK9!X$eLLsz)vIObA*I7w1JK-#}YIy$)n^h3$h%WENZ51^PWHbm^}rB1n}S7P|vE zoSbR0nV#3%iwrHn0sNa&URvT4;(4Ad;C%~^E8TirQ5)l~G<-^eeM1MQ1!zum^kUMf zhEN4K8K!0n{XX^1W?pz*nbl?4Z6qBi?U}kcAc%Ugn(@Ivf@(^y9(PIg+3J+=iR$XnzQdEuo(DZ8xlnI~eb=uB~lO0M3<{>5{hn+xM=h|E5!bJhPAV z6}F&@OKQwM4kW5|l+6}$sPY91I|_kpMZ-DMzZ?jcuKF|%R(r=LQ35SKKCbZ?amv(T zsuMxJvCPq!l8vo7MDo2Qm$kb@1e2$azJGqZVOLppOY8Z@K5VGxAZgdd{ zo>Yw-oQLj7szwKMitFJJzc)Y!XkSg)~@|sNZN%t(+>|x;J`TeIejNy@EP3$I+xZ^!qki3AL>eZ*00T7 z3vrW!-(_xofq44*=~3ELpG8v?AHBkraqV_B%)r9yB8RY0I&=$_N;IcHJKTgnTgDy* z%Lu~5#oF!jW;@GL+qho{z_XCa_RjSpy!+7zM4E5>tZ8hV-VPyj+J)PD`m9~jiHoTC zg1J8$+#;V#3!{XQic)F*%MNNXBW|E|fy%SJZyt($1Uf=H0bqi3QtYF@Pn^g$|An-) zcQ{Mz$Km(#6=J16H0neN`yl}PypvNoxM=$q>xv^y5Kk0;0Nqk~IHGHBue!$;9qj4E zJr&c(WjFj0@o82h&W=C8z7eYAe0((Zx9YRIM|chb{Q{zB;wiA^$ATOxh9ByW;ab|~ zYE9)_noWatj4V6g>gi9Ad-tadWn|6#P&>Ztya)a4g@WNenoLxZ-MMNKt0SdOr00!bQ9)K@21FZ1oFbH4^qoC@`bCdJIsW6*RrKKlnEWPr%s&JcaQS}| z_#X>J=O^iZ!vEHQ|Lfw12K>F&f4E3T3myi-H^v?uD-i{^?n%BUN1n#*8a}6}eGSMt zx!L=8$UjjB=L5W!CV#L2rUgRJpCbzU0%t)J9Nvdx4eQMoLhGumt}LJ)CYk!B4ch9| z>GNH^)hzkm{jE}EtG$3!#*U|T{_{QPS93YK-*Q!B$=>|(?joC!;z;oIYkO*k#0vpK z(uVuXJ9ply#tLYENu=Zgh&L*pN_r6I4hd`wM$E+@ymHeJc(sqeM&hS1k{SXx_SFsq zqJgaLpz)Ot9q-u<_S!&<)zu)`vjrw3*tv^Sk7Sok>K2wA92_%G9xRfArx-=WcREu% zcqjM+E^mTjCTnE-r_xrtMuTqae=5$t``lU6FQ-Y5iFLtw`>c43Y^1$rS(uP6rCn)a zgB(@ifxmp#JMxY}@LyV=c`Q5fxKWUpLftc$-Zhi;^Co2a4gptHt`lYw^FTT7BTgMa9(e$)9d5>$XSa z9@S%Zrey2ZOPK0OMq+d!cMhX+)Di~l8k6Y@8V2UUkJrp*Fff|fyk%_vOilyttx`1Q z-hu`s5G}a1K2lViL8S-7{APt;iql0YmO0(3pNS#}t7}~>n;S6EDo*q7ONB$?^;8)@ zNC9NJ)Ig}%v0}BIDcPSy?st)A%hwQ%R6{@l^r&@0GuXdU)~?4Jav7~FR9MZK%IcdB zBBskx?6wez`I_poUgdB4pxB*Teq~6~1T}@Jxl`P)-NHW4Nbh2#$*&00C3Eb)T*7Qm z-#h$5M4qHzo~>ucyTPFGjU-3yA3p1ohK7P-K6WeX7YiVYs-(F&5W35&pl2YGVmFEN zjHchpG@p6tN;%XonwL(@vseJa4+jnhm4zPf2ERm5uJ+ zUX?F^Y#(%@8h+gXA}cW?UmZ?442WJ1t&oR*M}He;oUbp(Q21*OpI^T?ElvRIsPq`% zXebE+D%btpAHEgM39x$E(~_p#-(i=GB*Y4+WaA-*{9v>$Cax~c5No>Z@L~+VLtn5v zYu`!|tFcB5<8Q%11v>AKDTiT#R7!-(au{uq;oyFcZJtMCa + + + + + diff --git a/LogoDesins/256pxorange.png b/LogoDesins/256pxorange.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb98e422943f3588cfdd88a839ec0457ba4a0ff GIT binary patch literal 3234 zcmaJ^cU05K7XAUj&`SgfS=6jjLv=N*G)WMpxDbjoAqZwgIvUDS1Of;O1_%+vMT$V^ zh*ClpgGwr z0Dz>GrMUyYCj)>0AhM4?axKxt^E=V2mTsW{AP(7U0>e{rJOGe5Z)J`?AIVxN7>t7T zK^U1EP2Gwjy3-#Q8iPS|`>t9<%ZgZdDJ7hhg<4#-2i;W_C>6Oe{n6)We!?vR?ZK~^ zGVq0qyH%&I1P~v5w|UK}URo_3^B4A~uPbi?UJ|onZ6*Z!e0lMVSMCR8DFrg=00pqs z-{BY$P7I`7$$+3)V5S{lIPtkbg>Wrj-Z2A;W`TU+0M>aUBvWvd2p5)e=mDn-a08z8 z7XVbarMFp_fL8+pJT~Mo9RMkb7lTlYQ*GH6rpvP{@u`YM5alWFK!+jl*x1t>bOZFT zusw^(2kF3W#$vSodhJ`^Pb&P9a^O5@Y$G~`cp5(LeQiq z$-c^sc882PskFS{VKJ9Vz`s3Pn)wQd^_4~+LAJl+TSqaYD zcXA@+=iwTf0e^ffA~x4Rg{-37I-L|JrY?afCUj?w<4djBGDni2_MU=afC~qt+(}1P zE^!i@f_6s@Ewut7OPwd2E(rB})?xg%ElkL5NG}Ids1Z5ND6-pPb;q5n;$CpmjG7%z zf11Ugy^Yse%8pq^L2RVCX6Jy;e&<_hGI_Akrv^|)%VX9GA{|9u@1hA^+=+Uf_9Ld` zccJ5s?Aph3S3O&>W%`zQna3A150T}-#d!ke!c zqY0;_#IVZtII37$`%5uvRH*MBo^jqR$Wis3$#zF1 zDW99ENICpoc43obs3Ce@>G(sH(iwWvGU0sp;kTsFm<~CG`jBX5RRB;?7o457{d3p!xcT9K;fAd>AtfbEo>}F;)6kA zt6Qb2oh`NIBdBUFIZ~Ii^W>QEB7FcR$Tp{2hh$3U;ij@@;=zPR*PJCjsj)92!T6+b zEKxz~^*Mz}edt!O4<&7c?R-@0_*;=J8qB1(I;3NH&>f>d(dUf}`BSU?XAz3t-|qmtzOAE8wYUBSzuFF}d)UL@qJ>)Xf&9>Qk1r0robd^D=gz)FYO1=o0lr zb6MpyxIHMfLG~?yz(ExgxGXF-1Z@-S$HbfL-#sB8&tM*Kg>I!ptbP6iq^D5C zV0P(^r{x=L=N9+(>qS)B0=$=Zd{x1-;9?vDc>9dYmS{U&XpZ)fA9oaC-sIn7;LvPW zKRTDJ1KqD24~JPnx8~khEDLSiRU0zv)s+a6z@=}G@V#EGuba^pAsf}ykG3l=%ItEp z)rOGSllHGaLrcUhI$hk8GW|n0>g$aeurH#AXf<5p zghj#ly0c?-p_VO-iin)Tc|h{l=pBK++}#V73Lc_%o*QavCJumiZ8ZYB>)(0wi_#5s zik`Cy_7i*sVVgoPJPjnnx~dn;Cdm-WicA?$D5t|Q`iyZ1zUD(8t-nl2AqAPfFKzH- zIpwR#4l>0qOSM@5@wh2X^Kidr6{5}K z)e8H@xwnCOcMv?#$|_UE(z^3ac)mQxXy$jUXi$Q(x0Vw(%o%Z9J@^|^h#a`}J3<^s z{l*CmzaXoeN!$J?iSzZ-By}i0i6zP9y|S%lTOV#-fJZgOj9Ef!pgYKPcM}q{>w?gd z8NpCgitnB+!CK`q(?y!x!T#s~JPCi-`EsM&&ciTTBg;2&(TI?sDI#G z`zkV#!g4_PCUzh9RrhMT@c(*y24;yzNJsd6Fix720-K0i8irYv)7!B z&tcb&ju-6PJN$m$euDT6UH!U{p9Wx4{0l#g#M-oP$gx@_aY)_>>e-{8qkE3_D|znJ zh~k{sj&Xx*X7h{a4~w7#Yu*U+W`w-U>523k^ttuGCr6ibv?z}yB^EvA~u0O zAqUbN%|@3baxP(?(?x~(QIQ%EZe}?}A9$wag7X;`J`J7ppPqkQGkzRh(h5QULts9a z|2KjEk&x8?BK=?RzjMI zC{Xmvc0a#PNj6UP0R|-EXDopElbSv}j=PXA;3YUa$(=dXyz$gjVB>eSp}n$0Ed65# zw9V@qfc}0*r0Zzx>OYo2kqK9d45>H&cr31WD;eEsMh;=E=L7OU# zBS9#jpcg;=Wv1&bv)M)shqA9h=5v=renqXCG)q_8%RXN`S({k{3{wMaaMsmU zrl7r|a?rUY&698H9Q@Zd7D}aArF4E^$`H;WLnegL^7w|g)84)JclK5BMn&w@dY^IA z0jiz|>C4xQj3zlk`6K6`n7PR6Krv6jdoSFwV1&IQ=%S+e3_Ia^Tq7_3L+U!BGx~v{ zChaA$5J43&(iDq9BP26^Mi#-6My%;+H7f_TO~OjQ884vWIs2B)2*V3S&9<-QV@Y>b z4oU{0U{@ILNeV84RVO0-7KOUOHNqsbqF%)%caVm8Xb;2UCS3UOHLr@5Tviixng283H zd#)_WdPgI<G(k=UL&p-i+d>H&g7@_H0s9#>Vh*?|TnuRq!E_EPrTwB;xR|l)jM|lJz@V zTx?BhzR5zj8%cjyxH#86-!$@7)L-KqcSG#}km#P*Z|c^&z{T?oXPNLEo}*X+`+#od z?XM7uUaIB;Gg7(m?xpu!E?&LZ7y6 z4pPJc`M~4N3*U!Nli*b8^I}HqyYOILk$n_${7++bkkMEKI-w~`$I@sW(>`SH!k2EAb)+TU~%8RT*-t`?5QD^v + + + + + diff --git a/LogoDesins/512pxblack.png b/LogoDesins/512pxblack.png new file mode 100644 index 0000000000000000000000000000000000000000..7254ef34152ea478fa2669b5d9934b379b23d0d7 GIT binary patch literal 6779 zcmcIpcT`hbmq#psN(mrM0TUttrRMQKB!GmLP!$Uj1f&U(4oWW~U0Q@dC=#WGr-1Mv zfHWy0CA=633et@PB#$CRnzXs`tu?dOeCwN;e`c+dm3!{pXP$4b3p-g75L-vMcD*!aGVfi{|?b7B6m4BBoxsGde?(T z7bm_y5bmjuUun3tsnrBhfpIdq#f4VW7Xg_8?>(pVeqckLM6B63g5w$@Q z9i$w8gsVOQqK1O@$TQL_@^;=>?C*N0&o>Pm`h~pud+u+SHry1AjWu^6qiW1nUHGGR zckIoEZ%TMb*>H}7i$dgQ&iBo0_sOx+xOZ=uG|mM%K9m&H5gMqN0%_|mr|;vHSP_i# z0vR{X7Cj)&A*Lcz+kA9>IF4tPBT+e|l=t*j?J)X>s&zMIQq~0nR8D-NMHooiV{7<& zJV0ZV{e7iBM_+>H&^bP!>1hHG$^ z(u!i60qSB#;$3k!fcO3KGb)cg5-t>F?*G0&%EIJRc zH>rk!sI?(Gw|?{-DPm8BK-AUhjX&pn%^tGf$YN83!lnD=P^hO|vEjzBj)-I$kAUDC znW7M7h|hbz81JmuSSvvFv1|O8h>NG3KDeasvAdaHg_|#`yuq z#`;3?3>$lLRC(iY$H0&osliS)VdTA=M#*xUIp;}*0#?64@{Aj~%z(X)b=HE-qu)7x zn2p8p0Yc!zzKppCAW>nWPyG2kAFIP+$pIj0(fHx9Vk!@K(ZJwZE@$%F=fJg>VzHsw zW_#p^Stg(G@T4N!DlYYTz&nY-+05@&l$xoyw|p$X%7DcQ#`!|XpJoR0{`^%der7s9 zoSGmdEQ&j5M#??8uU<2^0%sy$77;xAyAFnTT6TEW#UE+46dkSlLLHVVnBmWVG6zl8 z%#FqUytmumE9AJ9(nRh1Bd%opu#79&%fd(=IwO_CUF;D6zXX=wY(FAyE>3YbF~*18 z>8$9#q7-i*4-W=sS=}wg_d~xseH0*3tI#+1PF@C&MH>Q4wl2kZ2Eb8Z)+qOQzFt=0 zNfQ)B`(b5B?jd~PNhJHa;6r$R=4|F@#3OG*qnOttQ?~J>kf+QC@-t0U_Ge3Y4b+rN zD>8Pa(DOqfSuQs{3Sir+cF0qUt7?7CRuoqU>Ic5MA(9T-BBRCJDkAUT_BqWx$^(R@ zzjJEd!FWmey^C1J&eV0j7nYbd>e3W3Vy+D_A3KQ4Ju2OL&UY?2Xgnj8HzLOt zDye-Pareu;xYKB5(6&z)OI!DAS3O!;I|c_ZyR1v2GkzIUrt;->*@b7E6G~b=PgnG7 zD`9rt-K#9e%-b}<@%&0R1`%lM_|-sBS2-^27Zcyp_I+r&vr!FRe_kgQVKHCzoAP?f&51e*p_O5Iho!=NzL2+E(hsDUcj@Qt zJJMe+%;7XXtbR!LrA^HvrV;IdmyAI2`r<+26tK_Ja+wI#Z$hD+uWEYy)8k7^PP#$? zvHJo0OdAPiIV+dlP%avL()#B%e(9p&n)&!J>Y1hRu`mJfx(3DJRfoOU$DI7b zN!Wn||8AE$TDcCs8O^sjdeGJMeTKLDYQHvS#=%wYSp{kkFn^H*VftT9-_;O1rCIC^ z$x8Z~=BwS0)u_6IK(M&gVz&A72iNCu|KLtI{^_cZ? zC^U~L>Ug_Zz-sJd{dlpXs@;ZGpqB+V&!)?Sh>NTxSyX<)JHTml=|~*Y^g+~Q$w2*C z8R0<+*-i^OPThg(e#D5b8gPjY-f+O}*)j=fla4XgEIJTm>#F8ap zuIZ?4u1cjpDBtb7=SeF*>_E=EFQn6LRD11?pP1R0j8cilvDzM;n1WETie5i*Zl@r7p`P%;H7mtF!iIXT^1cArnAZ&Yu=O7Y3isPqNS zim^vHkown~`9iL83Bp#=8dXO1hOKr>g^Ju#5Lw_J_sCD{ZBaBa&D~3f6qXvrQt!}# zB<*VzpLDfGO0Y&w00N;@bL)3L;3{cCii0yrf#-_(S?_(%)E3M=W3k!u33peHJ>3=D zE~N&cBKF=J1_r(PnryNq)1q`^Df(vT>$Q~cEt5-eAHOAKYfWMz)rWU3fEoVje)R|t zMtD#`NKt?L6>b9>muhiwv+Zrs!NS*vGtbaUlAZ?BPI+$O%E|SjbSa9q&IY6@wB7KM zxqr3`(c60`BC>%W{c7+*W%vc%*ytqelL-e^tWq*3P>-do-z0=pV6M z8#FoT)%1InqIE-=7?15y*rtcO_cHil!Xj=7RQvursJj(SAlutmafAt3H60lp4xUP$ zqgZi%F30^`;}2^68PqA>-VucA*V=C*T;<{af11e?sl0V5zA@_%n1O>_k}th28$w{RDx-cV z{7PB!GhHUpxN0Bq0+`LYkp0xC#gL2}@~+r-mrDBP-dCLE z=Gi$(Tk6k*M*Y|>%{_G#?D&i^5)twX3dHRSa`WUT&XMu{b$Y?|JZ+?Y1{1p4rHet9P@)QQpL6Vr{$oeQ1FGeBgoFh<%M;r&f1;TYXBy+ zisXrfBEp7xtJWcQkyys@Xk4tD;_^kxmCLA1fq{zX<%KunO8U8tp|P=kac=$4C=Fra z1mPR{RTcmsyTQe^(D}!^g>3YulCivyet+h)^Orzz%8PO{lmM}=y%rjU1uzhB+0{f% zf(s*&&Ww?Yn((@8@B2|Ze_5GQMbp$nG{8g^_>(4^j5vih$u34oIN z+zERXDNp{T)*_w zoq=p(E`AzG4Up~^>}1_x67~w)SHVZNd7qU~)27nsdcqnc2L z&0x5R|5XpWNxuo8TGPI)avZ!q?W8pRfx7C(F3QIU*r{k4|wL53F?7y0`1rfPDJX(cW% ze8bF#Tfx%wq$|aJ^m(i7)S0mC z*}T(}tA>2p+?1RBUt*?+>gp(B$4i~7MUUeKfV`Q|pBN!VW;Sr^+!)(s`Q2S8kQC?XhL55|b< z+t)TvJ@V^u!e~ASLQA?oZI0;VzZ&%zobRXKS!?w6HIU|6u1rFAo4z2Chjxr?TN5K) zj=O!EG4k-8nx(ZgtW7N*SE>6(8R4OU*ztPI7&!(Mo$4@|5%79r(Uc-OvxOC8sFCed ztYVR$dFVUNLcus79Hrsyu4i=md$#w_jpj1eG2uJz;L~|0Xcih?uhNyf$S>=NY_IJc zVvJPi7Nkrh{enYEZOj}FuwL*`Y>v`kR$&WSBK8Qw=7bgI8(}|lN$e=wJ&TjEpQMGh zRDlYR9=k1v@GvnOeJVhAd0R`U8_Hd-K&!IjOeTW{E#ntAPmMvbNJF7SWJ6JX=8aezL%7fc@-$u?Hep$@h3SU2dB1itNPIRD}%!q78 z%sbFHdqgtTVM3?qmk__@Nhm(X=JGUX=4Jq4N9-|Pc5K$=Jll^Go$_wyXUem8C`@L- zg|Gpu?wq36g5&>;_3KY*p(X{O+N-qxrFF|jl63X)39w& zTKigL|Aq%(j*Yg`sY&ib-;(y{f;KW8|E}7ThHbav{q0P0cg}z5{e?21+gdX3g+TPp zkUXZH{7mJpU>dY|?S4p+Ls<)7><>-d(tc&d8G`Rw5OoJJ@I4nrOvI^wGX%JITHUdP z^l86EJQK{f*kb|D?52~^VC3v@@6n$$y|vWs|jy;IeqbGiL%2YvAFISIDRG3y@vhdHc*_AHN{DZvQz9Q zeQd0OXY``jY_t#Xg}utZU--qs-*G(I-t0vGKuRL{D7XZ@_751C35L*tg}%vv45cbd zU*H%6U}4MQ*SoS5Ezouef57 zV(;@QJL5WpgJUNS6IX*O>WFPl|PYgZK664lkV+UGIvM{OA_4(`j+tz)h+oW}Dsb z_$o0u4Wa!kt2XpJs5Pm{d7gN8k9SE*tXn&DSR=Ce!)oEK#f5K^?V^zq%2(_#; zv=FZ9sr?&&2Ok|JyXPHD!u!)yA@otR<xqVn`*hvT+O<8YH@RUa;*P|8?Vz=!++Q+{RbJfRGA*kE|& z1YRAY`$)|Q7G1kW0ER)0G_2DyNBr*y+@CQ;IXlaeQnA!@w8+Ha| z!10a^1mB775fK--W=R;6kj)}_J>T1UKtQwe$+|p1iv30^cbAW4eekP_z1P6{R z1VwNoSL=@jFE6b-0=CA=cfxEm9v4DI`>eT16DyCcOh^^sLgg!`m^lM{;e84A2G%h@ z?fGw@8oKU}CIir6uCsP6d(B|#>%a%=wxLivc1ugsj?R~JzKWi;d7E!tS!GL-F6lTP z!X&6Drr83XF?DKCVPgB-_PLbY^wz{z-K(OZYTf16J?#EL8iet~-Ce&rJZ{bz1MWen zpoJU}mf%$9#ghdZtc)Rz;@wvkdZ<=BS+fHt{t=;#Y--E7yXVb~rteUcjX_J7WyQkE>7L0NM_#2C+cPLteilBFCVS3tT5dvH_xmsq77Q zg!m=kT)+0cN>kH6B{N2~o)3lI@F+O9UD+nDsy$h9`htZ~Aj*6(8((OayvY(AVz+=X zB7+K~#WZciwI#62X*00~I4{u3`>VYy>@#>oRS_ub=j4F%Tt)YhCmiA1^=Fawe(`=9 zlq<*HHH}Z>Qx+2KA4!c0Q2Lh(xLGeGStfZvN((2zIOP1iVJSbGEtEhDiwQ=(+Fn zUPG<*4F7}q(@6=3#BC&GY=h#Q!NyJVjzxebIm5}ftWU+35 z{T_0v@k86CqQ?6-080@BGo)3i{!i6m6m49WCUm?=SzpssgT#6p9a-Ve{~64%*CGM^ zdL!#bt_586KpG2fcY4BFYu8zq5TFHB;%#UHZ4Ak3_xR_?URVGS*~w + + + + diff --git a/LogoDesins/512pxblue.png b/LogoDesins/512pxblue.png new file mode 100644 index 0000000000000000000000000000000000000000..f0b951af8c1031a1676456a06508adbcb36f2074 GIT binary patch literal 6605 zcmcIpc{tSHzn2!ql08vPM#ET=OtPeal86{tBFSE9h{iIFeH$6mloSaggpf2O zG1;jULS!tVZ1>Ff_xs~M_n&+3bD#S>XP)_-Gq3k@&gY!>`*q%vXk%r{&m+mh!NI|g z#h~ptICjA~I5;`D_kj_`<3hIJ3vw0Xbd7_9SD5|T)jJlm$-yCU6N@&q4;!8zv(7wZ zOmAO2nozstc=0#SV>0e?1?T87ekDhP2C;J&c1?=eKz;E}yC!okiz+^N73-~R&>l#1 z3X#|}wZrBJ0uB7Gp%h9+D1I#qaq!TWVg+@*7tZFfQ>z&-3R0M^sV3cr0 zO5oah`vtm3T}7-E{IC(4>4^SvbiF(*OSY!!MJ^appjb~P?w_>G-RxB?0%d#N)dYeLmlt4&rJWC8++98Q5chSvO!Svew>y_@&yejwQ;?P!R0# zCr|4X?j+sx-S%mHsc0QXJZUANi(URbXKSe6U;ZpRKnI3u(Ljgv16|GfG^8l1g}bGa z5K@THN>|4%nP-uqF!ysv=Z8BwJwMolGIxNhW&cob&Z3C-j? zWgQ|{=O8Q`A=pzf63fT$C5OkScvij78fm8(O7OtO(bBozJF68wh6*GUS z=W8wpY#b_0LTK@`#aGjNkdLk$CF~p6!wqp0?9mykPK^u5z~fWz`Q*k7w^PO~b4Na( z&5R|!JyGm1>(7f+O)nDc^)XhZ(xr@yYRpiQ4q>4Z;gnum;Mtu6J?Do1<&3I^L~@1F zyN_&#`v^YJNvIL;cOYtaT{_pKwwE;OI1VQLxP3m*IqaJTti_@#d}mcbgyavM6WHH zI=Z_ZohO3QI%m?E{p&XKK^Fuzf1DDY9{J!K+I^0zWkq%!=1`s2Ozz88Nw84vApWy!BU*gM4Au}yGroiWZ!Q((($@U+!v%3r{w z4SmzG>~$tT-t3B*Uvb{sM%R>g#B}IB`BvWDMRsv`YWM~ z7EirT+q^9B>qf_`_ETT$vwR@6|USXEmI^ zB1=`fdo4P)W9m!vjr~b@;;P5WAa(fo4 z&n!*as51<_ZvEEQp^Y(|A2pVi#lu6Y}?G!|MJ(>owjyJ{cVPyS$| zrY~EITgdHGqH6maebiqdZ7zgX>M0f_U95L%@)vo$<7<6IE{h8rll%UFy8oc-JOmp# z6r3`~6h0L0ul_S{{_+-_abtdle{xBV5eVLbL!Nk}c)=7=%k1z@cTvT>C;epyE3LHe zx0_?Uo!Hu6sovj^5`xV<<91$*)>VlHY#JhWpr5Z%x6N|o%#n^MClH!m#EbM=TJ4BU zevHHzZMCR9mbh?v-l6TYzm=AVolEyhq$%%WaJ`fA+WJtY=C=Q$@WHwCGhmmD+||xF za$Vwu?hI=nLMun<#M(P+K1-AGw9QC>zN-}+4uWMhV*JOvyx`=LD&uv8O*kybXMc*?9-cFe+buZgPTF3J2@;*Za77wK=UaasME$Fqf_^ z3>$mXHB`^{ge^zqd&pI1;p^t~t0^pJA}Q(K{_kZYo4q%sn^fP4^dbYU9F68VuBEN= z%wzc11H9^#VN!=~JnSJZy@<~UGrzmx@ObN-A3%(>FK5%WxnW&tn`)%$z5|}?V4?ET zBH}*jy(zujHR#!nw(-GQF#eU!7P&{SDW~Lf=#hS) z`zsD$?JS1#N6%sqbp?M-Hx?{%_gp+0L=P5Nk)e5|7tJYCMUw9SF_noDNDP{U%E=^Y zcPA{HYxB;a#Xb}^jE@@DbA?N%%h7Nq&hbmeumTKE;CMe8qC{EA}FdU$9 zL;l_VpYR44jckTr1qf&6inlKq8ttVh@Y*~+$#d$);KNi094%X!2fdB&Y1+xNM! zWXsEhJci%m8y*ypi1)4s;ZYgv((9zj(8|V&Cs$D|B`uY%;rSEYAf5J@?U#bj!6}vC zx!N?0E}&0iC>OZk1cmhuu{9CkO*M$zGmBCTYoMd9K?^LJ9Ie|O9rD{D)w>-6oj zX+s{f^0$Zy(`q^!fA)+Il|>cGHdT?_IAM@(sQA()UGp?I=LnP(eB245gIQVzftlnc zss0Pb?}lc=v-TDw=(Ud_(=#^AtuO~2!{}y9-ZIF#P9}VS&A3{LJ!$X(+|sFP3ZL=2 zedA6+qe@1aUjq6E$f~d+7V9`8d=f!XUesVL4CiwXN$Dsij;JBnk}`4L?6g2~8-9M- zVl=a8^d;bH({3iEtM)5f@3Owx=3e1E+hG%b`>>s>bnYXpv;GUoqgO#B3n%gZkwL&i zM95nvCWXd;qZx)diq?3^{o6o1Fwg`-#MMh!Zpa2vL>As}(8#2H z&O2G4^`$p%_IqY#D+J=Uzk54(A0cf~&N2ok0SMuqaVMCZkcxTb$shd|14s> z2w6-cfP3T8@CmTqHb9#&iN)9E{_ifEpxsACNb4L@qRo>z)`dQ@8v{Uba8DH&k- zWoSKW{#M0STX5I=k|g-0MT2dz<&y>g?^0hu^KrN^-fmDsLg$Jnl`_G6%W^GHF&A*f1`Tr zX?gr+-aoe%Ba!>K=LeC>%yd=$7f*3EDBtp_a!TCs_^x`@wo~3w>A2@@%d(6cBV7?>&)kVPnPwHaUr-Y3sn6$!@~h{gCu%J(Y4OHOgRQ+d z_er?;2=S`WY5Zeb%v*j3A+pk%(yU+o@qFzWiX<#N??Cr*YMgguqu(gibO=QXlp_z! zmrR>zq%`wj!yJvnLL0}Px)n_SQD&YGxGrtdgc2ra93?-z6IycPg4vQe2zM=&K|sMT zg2P1C#|&Z=P9iXj-VV(%tx&a+hi^TN^X8h%@j9O%L%qbqcnKRH(p^hUh2mGX&*fpm zWObH3jMzHGx(TY^uRS@W<`XDHsu_IVQpvvGxo!l$QI$ZwFr1xqRit#nwrC-IGF0m$ zMbQ*7@^5(>ZuH8b8lotcr<+GKEpO+ND2Zhe=J+z(aq;?%b)Xf}tw17)Y}&+4jPrCW z9ALiE?dnwKH^h`Jh#w_Cqv!pOd$>-?&g_|@2EeLoDTT+e_h0#08wV=2U2xA=Lu3Tq z;OjN&v^{*2DxqElFWwpq=nouOt@p<56MewhSh1(2@-|^cmLYN!H>(XR%4hkRnV5<* z`v7G$UoujR5){UJHxOo!T~%X09PbcWi>$euHF>{>8Y{c6K2Hx=Hs3M3mdwdMb_*VL zLjnEE@GlQ%B;v^TKmEFUht~Yf6EGd5gX|<;^(|}e4CN1U zIlbbNp2YOe0qQ@O;X5gtB=%uIy$LDsEbB@X0Y^?IaR#_U265r*wlMoB;ZG8fQ-4)jGC8}fcOna{37Wm?8a|C(zos{PSGzT_Zoo2<`eSn5Kq6(W$y8tQp*K3D~@}`#dw( zNjC%4uN0TqQnDQ-g7VT-ATzF{qaZp28_PMF1%j7=w3O(0{7X667}Ij z!N{hmaAU*bhucDO?pJC4iP$4>CM>=PA5_ZsswK1~j}qLLKB~uN@C52h_ZG%*7u@p&aN74U=r%z-7-02)88eKzy)T6-YvavS4 z@#iwWdo75hkEm=Tz)RUoB-6A=I)XGoiOxxhRk`W4p<)>`Gum(JE}cscr?|a^7gzAg zgMF_L*uzhTpURr)E?vU(IIx6S^4^z^kftgx`;)!^Hx&QKtiX$xRl_Mq+h6VfGRSk3 z6-`KZ351V96TGQ7EhPL+bgH`o)`Hz<++Y@ z_JaEx)}ib+LPqJDw(&?Eq2w~91d-mWHu1>ALdkR`ZWupd1S#roH7nXPJrXO}d$QL5 z8ins6R07A_3k$|}d&8JqO-EaGvg?m8!pk%sXw95~}tFp(IbIvV)0j zeD9-#fKFZeZ`v@}j*?NWeSB|iQfAKqJdtHfep@wGhNc2*?p(jxEc7jD)Eqq=s{tG52BgX7TJTG@I8^}_zL5!PJR59@h_L0pjkN{+urS=c zeXgm>h5BHoFJFij@^zn}2siEf{IFK))n5b5P3_NRuWX-u9dNX;dbu;!RQgV&ucb3| zr_qv>$}{ufkO}8=sL7Wpv)p#;^AfGB=LEdr-N5GmoglJ(xWDA<3fHUPsRJ` z23CRi-zaB+US4gJ6|-qi-0*P=Nj*W;&NGuRb5+@Sv2cacpX@W~<=92m{990y2ATOF zdo7XaH#s|MrQ&Xab`2EUq$2Oj#go%Fi+3sFBK?ES5 zfgQN*t2|!Y_h;1X&+U6+Bz6Ccz~P$vh$pL_=9qc{_5|lk{k9s7G8E><8`aeE)30HV z1|qBX!l>N@oYFK~haT8nM(_{i$VjWSe03?=x1X5H~ zZEq$q0V~lFCgESp1NgL+?V#@&G^khRWv^CdYnitGb6w zA7*R3Ln7houOr!pRQ*)CiuoSyOOF)nef*}%uMOU05AD$9##OoJp#>8Z0M=L*E`lgjw@2?38qBIlL**H= z5h=>X#y(WdR722S3kxd;V_`rJiA&~eo4X<3eFLs}@EnJ^-(uHXn(WPE zK(!a8iYW$aNAb1<$v)sILO5ccD<; tc7N^Jwz(k + + + + + diff --git a/LogoDesins/512pxorange.png b/LogoDesins/512pxorange.png new file mode 100644 index 0000000000000000000000000000000000000000..0f00865bf09c705d7960f4ed042a05011d2a760c GIT binary patch literal 6582 zcmcIpc{G&o+t*@^>}n`A3^TSwvJTZ4%vgqqvZXLFvNs76lCh>tGqx<_i=mME77>LI zGQNnZWbB13k&s>9d;0zJo_9I#d(L~_bM86wJoo*%uVv=BuKT(^PofRZOh`alfQySu z2#Z16a&hf~adGYD;^P4`DypJq!54oZ#_<{#*FG`MXIJk~8{iqP$fA4MaTa}`G_ujk~U7ck*6KlS{P=aR=-~U6ghY z#Y4iO&IMdznbY+3n`Kp1A=_r>tY-}(x|a36-C6xH!W+t$-9n^}Yqo!dsZ(A4`7}`N zz!Sg74ISGhx1rb`M*SAGY4L-a)BS0{qHHe;bwJZeu?DmF>u}V-EUc_QoP=*VjnR!w zm@H4IHyk}e>Q9<(6}U|a6cn{`5;d&(*6_tOYp|E;1E$dlW zk9Ug>O(u3-TlLzqTQZYrbq!M{lY^L3gsi7tDFPeMBK=y3U-?DFTA>9MK-RwB8fp0= zVx}T=SH>o?CnAid*g%|~78Q$AD74?`79To*N07?)*=M)RDzXzl| zF$iNQ>>R8hpmz|yae1`Co`Y?|6Ni~ov!dHoZg9t1#nTvs8G1<@Nz(d)w~0exrX0~U z!4tqyVi^p!e6+x$nj0d`wBh4F-0uCLyE?@rMpFXSl!(^q9-H&%xhS5%xjl>4YHwz@ z6*QjQg=*S^hFKG(Iol5*3h}r;BPpRL{32pT@&#eFSC8x)Qs(DBBH07mu1qm$&ep1~ zd#cI}z3XaP_5oPz4J>B#Bza@}&cwy}r;)Wv7rtvQqKgUzV<|jp1H;deUtBf4TUi~&;w%{21aoZg$bA% z-g}80KmbI|qm~yJ1FkEp6DH5jNBh5@BvXu(3b3i9zepUkFq-H*KX$@s!*kgWXQ~dH zkVQ~>s`Mb`6zx0HjxzN15 ztYA@R^9Adwq{P4^;{t#_N@_6DA^F??d>-MiLnht`4S~4ITpgudYs>L1)9;sJO)?PB z7uebJ@X%Mk?~g0D&)x2hl@fM;O668Sel%na59CP5GpfeFeiMJ)c#8eJF_yX6U?r?J zvwWR+@ZoR|-!xh?{8{&roE03a=>3=Fb)MC>Qqpj4wcfNV22SmK}uhj0o8@qgZ0Dc%{ID@@hBas8@Jekekj_ z`Fy)>X{oMbHcg#G?NNR>?Yz7Zy|eWTqx1O)wm!SO+Iq7V)<^g0X0ss7$#|H~oNGmG zY$Z#3@AlHM_MNUz0~KOSzALkH1KQCWPgg4Ag4gxiQ?gr@i-lg58A1u_&Rx$)w(jyz zLGC%>9FV8D{=~2@-$hno-LE3E-e;*vxPW!Y)-3VsPECOCD@V(xnp@*O*S9m$^3S!z z7$p!RP&0DpNa5X9rywtrK`s*Syn2;qg#JZwu4F%c327BcaBSwER(!aV6g)!07;iUe zKZ0DmGH2h?=!er6w{`AbCYkN~8C*4dOn9w7UGKNwPqBmFQ|-VLF%VBmJA57T+;DE8 zFTBdpQeF6+wV;*hQ`!~@pyTy}!>WcazJQM%m{Ss&SX6DlP8xccDc)-@-1hxd>2~~D zoLWIFTKJ&?9&vrH$2vWqsKi(`RBy7UW^2_^x-=iFYnza;{PNxFr}XPGNU6*brp>Oza;%H#pIS>EnDT{z3K%qjx} z^lq3)VQ|W23_%Q!Xcn>EJgsiFcHAHvAXa`Ni|6*EFiWt8yPke8xFPkK={=K-i_jOs zKYd06(qm+@3w@M^_8Ud`pPZ5CwXw$j=!HEV`djv4rXt}9Kk}LMFS4)kT*TIyK7(W@ z%cYQ%sH-Ohq9-$yWsK_+(8#!p4J)b|gXA`}*4Ezgjm_512O9%J- zR{a2D>}rtYG2oWUO(Z1rplVRk-h+<^_q0i|l$ka-I3qgJ@!*8S1)`z?D_mL=O4} z35p~HKyx28t#`?E9j+u%;HX6REKdd=ktf-k$OwEd^lioKLe-95>;08JSjI8!fP>m#tI>Zy-S@$ODnV62c+$_#OrQGJ5K z%}vGig8_FXn@%&dlC(9vZ<%`a=EowF`CTU*bQ4vE?~?Fr4KtmsO2tx|eAw6L=>76PN5D0ABBO$p_( zT|{}t%J1ejqwQB?f`2WE_s+=gRTR5MGV2kU_x%$8w1eqL zhxo23Lr)9M`|#cGUr}8A_rB+KbK1>C-V4Sp3Ktk6Vw{264aR8<7Z`l}oB`bh#!(p8 zzsCO)o(noQ>?_6kctyk2iT@Dosp_u%5gAPJ2b4>ZeRYeHyJ&+q(WbAE7Qq#cmggM=aTwjO&?;Uxc-U}U&^M6s z)9m*`$IgxQ*CWjrJFaL%V$f(Sq_AJh!b8rQdqEOzkku<>V) z2$Ow9=)b!BAElCm?L(uO7ASF#Slu!0o7vQ zUT@q7t13tJY8AEu2G1n8l>57EycRn}Y_+^XZ5jf1$ zapdORk$QgI@BBM$If$B_|Ea4t69})!T7wIZb9pwe-8&^D^{}PV z6(x-ebr^jKJ#-H&!jQ&6nN#5Xa^t-`q;<%fu|dUi0{vjG04s!ldTq=xj-%2f zTO69bAlP!5{Y0F)AZQZg92ZP4&VG}o5QM6=FfCgPk7Id&wccF0thSd>Vz*y5Ew6Xb zjp`=7#NV!UL81vv6crsTp;*S4Tn4$jm0}ed*96(F90E0)mFz`b(R?ve1HT&!95s^h zL50~>2A?^q_FTTfp7)tr&8QFE`Mv!f?J2Dq_fLnGf>n&_Rq0d;+xhRZ%!TO7OUJA{ z-ZToy941rP3*Y668+Y5=UEhxlBU=bUYHA72B&e z_2RAf9b}mGqo@H0df!~hl&S8$Mgg$hBs9dxIlwJ;(uMvw1E>YN9aW{AteUt z3hN3)b=X+{%chDwt1Zfl7E|V!`pRS-q`{?>e+n;1Ka`+Gerl>9eSd&=Nl;*T2(-V1 zj`iqF1Z_XWJ-2h6I#EW)A4;jEC&mCb~)CIlQL>oMiK~`WY3rn z9j_eF8O9q{(+ABldHSeLvsdZF%bZxbS3X@6nbst-sxt=z-Pv3tk*MOuio@sbp+>kCB+ z2u)-*rKhKbc+xqbn|gCZ;0OpWveyXEQRLEtZ6Q9m!k*t(b_TN+8oJT|T(f-g=!8<8 zUz@?UO6N%d5izn?-JR(xoPYFYMzNPfxT)={Bl9PPq~PM5x1r_Rp_5VU03loatvf%Zwh-Q~|XZb57m@7dT5DknjFsCGWanb&IlJp!=p_ zv(j54=w|*XS5)-FS9H3Er;S6P zAKUw|^Z+SVHaL+#q??w*x52`L@l{w#tnaTSM7ug@tU#pUe1p!x3PGolPfrS2_aS$$ z22oGx+?lqOZ4g!z=+;Zi-om}R;4JV+otfnwBMjg91-#N!$7X~|uz@x;i3OZqqQDmUNIVAi0e zzXLk}lGbT)0Q!#nMMCHJ%dc8(P^Fo}jR z7tmU@RY!4{<}(mxAX@b(iGK(E)m#Cy z9;kk@W%~dyF3uuw#{Jl!Zq|o3H8nF0xn8Na{DcokX4F6qXf~|T?AyA~%kjVw3p^sX z!yDpvhL8WqgrnuaoHX8lr6)~LDUUyf2 z*eE8iYJmRb{MkgeJy8>h^BdVKQoUV@7pmOFT0e^BJ&ntB^J&m}^1az-Wo+GOnj8~b zxpc)gLH92mI}^^&NNJ>h_@MxMwz=TGDgdZ1mn&AJxr;Ub@bb4im$9oIPJ$HJI%{zE z+b%a!iX1E`B5mtKeM?fE;!!t8NwfCzvi2B*04*KQ*|5TLa736~mdmPE*DkrGj~g`G zEFck~bH2);e{b39sDH{|8CH;%;dqiXIdx+gr^v{)nq2WUT(*rXQ2t9F=O7sv4A8Y{ zLSD^bm%}bgLSbf$GogL{^&R4K+|UR^;wQ%fJAh~ngQ=O-Kq8hO%@=)`HcPokuB^}l zxt$>;yXAQP^F_%zmwnS5vn&sc%!GN!-u&6w(qB6DB8v0_#qO`9A%q^q)-i2TrG$Pw zxMzxqB4ztrv+W*OJ_735+aGSss1>c%>H6vC^Qr()DNH!Ymf{gCM|5L_j` zN=n9!M#%+09aEGAW7;fOo7w|ECK3s%Kou%V(@g!T$qp7qDLb1pZCYDq9nj~~ zZ&S>rSTI0J7$WTe{$nB*BnKPL)g6K)9`T|ONaRrfRKP5tKF{zGKD%d`LCl2^z<{%f zg#ILKWC=2rB+~2Mtjh}NxP0915frAb6XHp{cx7i3V + + + + + diff --git a/LogoDesins/add b/LogoDesins/add new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/LogoDesins/add @@ -0,0 +1 @@ + diff --git a/LogoDesins/logotype1black.png b/LogoDesins/logotype1black.png new file mode 100644 index 0000000000000000000000000000000000000000..8ff176ca388b72e8596bf4acc5351141a1c28586 GIT binary patch literal 7616 zcmbuEcT`hNwCH2`1f>NLQ9v*h5m6A3@=+y-7^)^zY0^cyv_L2pnjpo{r3q35Dbj0# z6hR>r15yJ>5CQ}Ugc3r%2k%{X-MiL%|Gf7{=A1L-%$~jX>@)f8HxKnRSNBXTPNR!RT}+`y~yJho|oYmnVrYBR@>BVJa$a4*eQP zdA4&jjOXruE52E}yI8zraS=LDAzk$@j|6Um0+VX~o_rTk_cHC4(1FNeQ(A9tNxwA% z2$b3XZ`UY?qk|*50A1!6*i)M4#5j|N00w}Gct(%3yf=B4t#xI>x===Gy;C62-AHGN zW)|UIq0E&1pA4|e8*@NcNZHuhFm27(|95%g#_c*{HBeVXUXEsQ@O5xNz*NN;J>V)K zZj0>|K!cNGj`(&*+SomK0ny)mF95D$<<=*95(HxOjEJbq*-od`mNT$B;VZTY zy*Y@Jn(qNxI;#-pls$!$yR|sAk-+odSx*O9xQcf`u+UzDa5D(>bv;~Ong@w&QoM#EHL-&x8P2RWsN_dTF zoAZ4b;0zuf!^Mpv;uXhrMk>bQw#LA6hSkm6wC(ekVE9zD5D4_4L@ON8>+;lr2{z5> zk)NTx>*l~DO|DV|G$IID{RTG`9SJlO3FZ|~l9-XP$MS+epJY1d1B-CH4{-u1QY5j6 zp=yv3+c120&#^fSc!!HOekuAmiTi7+;#FhFfBUgceb)hs)pae-xYBnEOwKW1xhWYAyz|z65_{Pj?Ao zsl9{)XyiMuY9!Z9>WTT+^#thdrbltg*PY9Bl&Xt_gdx?j2N|DeXz19ByU%BUu(Hm@ zuK=5D5>X&hrlUV@Gidv#_0!U~=@IlH3xxSIvlJxMpE0LA&_s5wQYfXH+*1+C1p*y17oDw-246$~StxnmrB7~~g60vjr*Xd%)5 z6f&$)QW^@VH?%%a3ATF)da34-gJ9?vMhLU;!RKl+;6@-Q;q!aeht9BUb;g4W*VZDy z4(KylA;&hk+Hqh#_M5bOqli*NK+mX`q(wBK^!P!bfiQ60)889P*RyG|PBv2$C#>C2 zXUjG91cA-q61man?xVXFg5HcvVK()#C(#2NUQ+4LnJWN&Z$dM;mP^M0E%&3+{d`1r z0~@e-t2QPOC_^h!x=LEYY8~-Q{7Fb*;FOs!vtp&~U(dE>^~5f6QD( zCt`-9=gDtblScF>YURT$>lQLyWglYs$o4EPhsj%r6Cn8km;LVJ`zs&{I({*VMQ(z zn=`&w;coqm6wP>c{dUWaUcjQP=v|@#j$;XxC9he zI{m3goEU&!qT?> z{c{|=QY?`?sbf&Q91O#CM9a_1c94~+l4eytmY{}zst@OKV=*G4rY;a&O`TFWp59#h zgj-4A!Y1MkKN+^`;GlgR!GP+jnd4n;!Ub%f-ZTk7Qby0M@H#2=!iuuQ{*<27@=ribDbYCLP!yN@znVT`i!|_nOROng; zzCFji-NCFc5M@~_!*-ahJzb!|X#FD%^gBt`zW!I)gAhL@<$$Jos;vEGs7d0kA|zCN z`7Jgtt(fc|y?#|xtVvz4PGsY&N&W;F+L^yGg3a1vq2HPXw-x7nl@6LUONNBPG+#~J z!#~*5w;wgP^@3H&p3Ic16g+BF_-$Moq*&m?puit?X=v@U@r0F6HR|2S3n*iI@^&ls zT)A2H?nW}qf~0pPM3Lx+t$s>9v~!RSVf?&&DS2l?-JQRj^{M{FsRA6+L?;+pX%)QD zD-?FI#R1)SW2#J{R#cmAQtN&A7C!EGcxQWG+_q&=;FaHjla{HRJK{qeoP`P^yAlJ$(DeRoPj_U@bNs+wwyOif(>;Xswww6LN` zUxZ$Y%%(|_PieEzS&aFlbkWY9UX5H8MSp7Ad6}if=+p+h*M*4Dm1EczSbd(e-%AUl zDfok`?%|Vgw>bwbcPhWuTH2aQae-DxIJ(A z3Lu%a%pWQ*oxxrXNPgyaqdg|i{@018pDpNc1QG>&3*rO=cAADLa&&(>)83_DL908j z@7oTR?Q8UebtlPBj1+XPT>k+kDGDZRB6|CR#AeO$A)3_0pylrEGW+Gqma;C>*Eys) zpY4yuPgYn^32K{h50_THRh-TigE770-5x+3eB{%OE5>oV83$ykRpvnnMuMopcL|;w ziM{77ozBE#sWT1m)|WH6(q}I}N z(}`?}s8w!Yg5b>9JhN;>ZmB|yec-|C4eGOvmc5z{g&5_KRXlE2H<1T6iaoK~8sZCq zO^m!$Epf%l$|OV`cJ9P~nccXLU8!J^)@UB442pJkPrr!GY?`48U5|L~7YjD%)BPKR>CawP}+^SHnD$ssAWHK&FhNs1`CSNLYwW9p=y)v{N;88wj znOmoQmF2ORB+)&hH>qF$UsYlubMo4=ksOPqkwPS)nN*BRST0p9vD;I66ahAZgjVFy zb}{E(2`L*ryx?t=8*${tXpMZp)~KJq&@vh;H^E40(AQ(Mp3%_X>yAi_UaM8vmRx-% zkul956;R6G95g}V4&0XgLRncZm!;L@;waqX3%CUGud|tXa@|%8d|nt?Ur!c6KCq2j zbppqPyCYwqO^I;Os9f_3qnA1?`@k=bjgYM4+5XBI#{cG4as6Bi-5dEji z_Y(V`faan&0o?r_{t^CGYwhiC7fr~ z#OI~)wbt1YbFcf4O7l00ca#ht8z8TUt1~LrRV0J`pg`;uPvq*($lu?bw8vUSFKrPt zrc(R#^BI28%ye?PMc7noFs7!hr|F}&6^gxL2G6UlDr{Na3}JG!Saa3kX;nE<8s#fH z|Ih21bHn77%5HUnQ5a3EZ?=WUby^N5=v4S~G*BNGvuF@*V2didFPhT1CPGd1m#kyK zsHr^ijB_{ctIGYVm`87oUTb;Si}4ih4s@{`a)R5kIVOe4^D9^sXP%>2;1PQ=^|4xZ zDZA|jg0M>E;fT%7d;-&m ziDqvr#Ld}1ixSFFEi`Wv><{S|2%$(uOh4)fMlC&nkUgJu4Wa~X!VM9Wv_e+yZRI0p z|92%i66P#|jFK&s#v;*w8UBh=bTH>X^}LXnBkgVW^Bc9=VrHBt)v$wQd+9src4uhB z&8?Woz`3J}d?;ZsDpox`{Ep-(LT9g{|C6RO#zW->dx9udrs59C5>h6pUdV=?+7p_6 zNwhl9jMy3Mqi3=FxKmjnZ=|syI}8amWvCULKQo}^o-4N##~FB-C`pL2ARR%sa4|ex z<{L77voS$e_w$;EMoY?4QnkYBW0^C{gb!x_Q8Eq|a6K0tY+!yu+q+AM7?|4P`TEwg zC!Lz+`*jQ4mfm)XHr!qQ(b?q-?zHoi^;-et^cf>w?g4RI)T{tMft%g7+6h> zNGomjE32HMEdYVnEx$TKujNL$Z4J2q1Dq*^4#dJu6#FH1bFacT@5n~igSs>uDa8Tf zI?5f&wfhdPxZq`xfUFLJi&6Fc(fshK`cz8#usN$!*}=2^OfgF4UO(`!>>#*LkpI9&bo!+DJwEb%}d#-J&ipWoTqDnYJcO-qSR9Twt+Sv=&_w zb(OIT1z&U+{sHFlkNL^rSHJ$Qg(X{*zZKP!pN26FReWbzzv670(_WBhu{#ozR(e3| z?a{HNPxB}`S222t>^g2RHh@9&o;bo51jPU8%Y$wf$H5O;bJ5*ZZu zOi_N0h%Hy@Em+MF>k4xImYMoQk_#+y?S;kad;a$(5`==74Aer2g5su9$iZfcKwmC2 zBaH>;0$EJQ2a`9|8Li=Sx}Bt+tt}M9Ef1COZ#1JJn{fC@wxN>TDtgP^GjC+@s~D@D zrO)p|qUN=NWwnkeTc1%veJWVqb$4cvBJE@JwchA3oQ!mg+^EwlLYKN&A_D-&>*spdG~0^2l0<&q4TMpI`RvD+hBchkkP#uX_xx z)R#WNm}MlVUiCewlF2inEOLWq>L*)fveH!!80A-v zbvy_BPU5b?w)uMc&!Dl+x$o_UhlL#+;ZP+v5l*WT%w7$N`FKH#7^h7eY9uwiOlyV1E-dr+< zDZVVTQ*E(JvdCrdzqRN!sa`0|`kg@PnT(=8cjeK{P^>zYbv`;PjQ+n6S+MF8Q*OY~~B1_dml#{{6n;%9#JO4<3@G&Y@bAoNS4ib9eMA=1t zbw;Bu>G2eu$O-05R)w`YyHdJrNpU{XR%H$H6M zhYV4->ou?xhhfU|%o1=LVT4TPbaCWL=8Zm^$040A&2RLQf ztk5ST)slbS>Jj=+YCC?5J(1^410M=Ke`Rzyb>k1UrkKRZP%r(BrKWB?;kPonLYYv- zaijG0<^)YBUm^7vDryE%CzwhqEIm37nk zQt74p%T4x~Uc_PS$0`n0wK`IdE@#V^J47gaQr~X&70+{?ggNqPm!$e|`c*l-97Y;X zmzYCrZ%x{dLREubpV*WZI!aV`Qy)&q8>zf$ypFW=u?rSz6hZ70>W5K)^tq~}&lV3J z@9zI}3LCNi85|E~q>6MsTpzg}dKG)PPxZzWTZcGm)|cKOJWm?0qH-k^H}ajE$VRt#J+?7RMxWty>FS_qFHc`tru#*0|5|%73q~z7Fz`{j zV|{+KWY+u&zrQ?UopR`VrR&Q*)*sL0DHl0wlX}$S3RRgeu0#O5W>~>2bbWo zKWNH1?e%^AeG$@f_77uUPXp0dU=g-!;~*w2W)TAT!#?Ta;bxHOdacfdBb%RLdHfEt z6OQs7xck^ERu_(_y)8vsb^%S^JpRj0EdxfV>1PrIBX`uJbm}DTqCMFqU_u^Y9v0m& z6r3slg!F^gQ$Y2Ofw)a^-SnO2+f~;8xSP{3H#L6cc0UURckQ16?-ZC#fA3essu>QJ%6`p_@U>gA zzWixfO(56J+}UfU*3u*@$fU{OP~g|lM56IT5|?YYJe5{{*7Jb{jzz$Ep$cbUE^d?C z9$lLyR(4avl<6C0QONy4cW8Eu*irH9MvC|d2Nbz|xAOYsYS{@$Rd-5e^XKQRmbx}k zZ?))D-woTFoMA@xoH-S{;w3aL$wnZ4K)sym7Gz53O4+jP18XGW#qr=5MX=AYZuyZ4JFqGb{{YgS}E z_vX$*dC?pVQ+C5^T~Yogak17%?lMMxw?Yz8a~z@BY-1PMUea#4wm+ux*25xVkM2AV zaZR2(S)901A6xLooSy@B^eL13ONjE&d18ESTcv<*zZmt+f(8ch(RL|qE$gE!_vhYj z@sBsMnw1k{g@W9WW_-$_eG15(u6KJ&_?}xJ!y3hC@GH!Yf_70~Nekn!`;HoIy(Z!@ zAQ!P`??P|aGxD2~15;B;(do z-0A8MpPKNy(8IL5pEpWZz1b6nVDVzg4yNXW%g(9&BWB4?jAss!{P0vGx+%OnY8meB zr6OU*^GQAC*EP^qQaMv#$lcdle^{nk_yRh0`9{vw&Ha4c7XgNssk+q^kZgoDs&)ryRg0=0W%t#Ncdu-FF0N=5iC!9d zbIN0lecer)V)XdO1KS2!reyR`_Q%Z=PbSryo0`WjI(yiPisX$OJlEW8Ae z;$*PMTzixi&c(^0UGSWT?cBx`(i51R*FJKhK7Ml&H*b+8LE4zQh{nG0cL(wXr=f(- zB!JzTrp))yo9oi3{_ZImdO*Vv&=3PO%yzU-I805z@iK+%zyw>z6TF*l7W#3!6(mPp z^A!x&1Ktl=l}I@zeDG8WM~73{wC!x_xF3K8L+jLn<*+9e- zHdEI~F7{_7*kZ-v4{;O2ZT*T7ZeDsW_E+pOfbHFu+q~`PDX^E4 zUkUWNH6=su3Orl>5+M8Jhc}b{0fAygI$XmV%5KgW4nM{_CU*mwG#_Vg`K@1U@%<_3 zMSH?9> + + + + + + + + + + + + + + + + diff --git a/LogoDesins/logotype1blue.png b/LogoDesins/logotype1blue.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc48851fe14f1df6b7fff52ea80bb58128c25be GIT binary patch literal 7535 zcma)hcUV(fvv(8~5Gh9~N~9e{dJ&~J6*&qBh}1v;5s+R&Ae1BsB1G{33IZxkrGxa| zkz(ipl$L}90-+;F3n7%dIrn|u_qq4^p6~nq$llp&&&--xYi9PW-@JNgbdUWk|5*?S z#IAS$?jsQBBnZBn8 zKfbp!-SB1W_qhjuJucWTaB)91=YQz_k^gqyA6A!ccd_Vu4@)9XebWqyyvL=%bOU5T ziV{5EbA6O|!O`b;!{~;ZdBFaOJNWu4?eqfzZH+tiaKC=wW%6eOs%-l znfRP|*;VaHgO8rP6+A+kAdqkeosTpi-DtZ;Pcn|rN$FhqU*GBk| zWj2gG`)t*k4y}7<%5*HVfYbK^n{U&{!;XXvx?f=GpT{x-Q9BeW}qS~gU?N%tui4-#l6Ue@ zF9QY^{~6V8Ck(a`BImKOGL6Sd4$L)W<6F#=O2*sRK%ms8FQv-<{b2O+HN`0lwXoHA z1)Fe8ek)K1$}Psk=94U-S?oD|8U(7pKyk-Q_F8(d74#(o6HG_do~iEH;IRoh0Sa5c z17)*urbi#Mh8>9vL==^y0z4dIMJzy|DdU%$o`ur(MTxjX166Ji=+idW{BH|Lb4dKn zoU4FmxQcd6G}f3+%3OL>!^{Sk;s9pL)9g51X+CQ0u*DH-VrL&q_X7kOuEnzWI_mX; zP7;fUbP1{EXb0iEtb65?#!k` z)m#Y>NJXs!A~!Vu+=sF57i!5Z23Ne{GLT>EeXA3*wtDbY#r6cK)gph|jIdcL-m1C6 zdilpkayH|aVWB9?AYNMCR_@H%y=@|3=O!#p?Q& zyo1TlGUE5CM<`Vg$oFK=S0h`+ef((rAzu0^TIkw3VZR}KW16U#%K=Cd?T`VZZ0)aZ z7bT@Af4!>b?(i%92Qvs%nce5R)EGXt`3be)Pu;v-F{WHj_cJwb*x&`$&T0@!r?x_0JzbgUI*XbGd))Z?3a*ED$hz0-kM&})7)zT5yaFzaQMeABhe0B znBUV*pO$>Q0=TAUzA4*QPDql}ZYYVS>gRfcbc|>oCMg2Y76T&1MZ0>^Z+r{ACZD%@L(R-i+iR?`ussL!lH&BK@v5GHO;Fh? zU}P>gg>=wz1csE3D+exTMcoFUg`4ULu>y&2>fu^ZB{nVc_1mmxh=}m4#i!Sia}Uj< zX8>=HWrN8bq8s{0nzHonM+O2>ZKTivQGM$|CD`?=-UQ}9@j^vUig4#RnWi&Lp1dF_ z13?ASxePqB9A{PG4uC0)3)qBPFM&V=i2(Zqqz2$}=YP_0QGl`k(EP*lf20|VrrDw$ zO;S_!KI-%9^8*=ERS1}LA=+pM*b9ZE%6Na7MdK45V@KQei0x{X>gzybg zO|RwQn!#~E(EpT}lzxgs?E^ZRr7gUAO_>FJJ3s3g?NqI;kZ94@8bDJZgFXraO9`nR zSW&Pc@rSV#r%RpPZ+;xxaBY10=kw2|mV7|){3}7{o&v1C?W+kB#TePzN@U0-;|qYK z0xCH@a)Gb2`+o2mA=vO4<*#9t=mh_Y_s*$;x26?UAKHC)5zd!ed=Sh@D;A@g3Z{$7 zi1v%hpsk@!oIVX})IJifw|ef|VW8WZTQj6DDU}su=VltEz8bydf&GzL^;*iqG|9R5 z^TEymgT}@2m;Ixhr4SNSL)^Yotz`Nji}zyTmRrU9Y^Ykxv+8j{)F@Gl z^Srj|#Rm8%^w`6(o!P)Qq6QIf8h^DBG#>&NG;seCuIjOSJ8Nl1wQ|NEGOdV^Sgf#h zano@KArwD|J@?s0ld33DlBp70DW5#DwZW{IrjsleJ5-(g7+h{CXv-7zgqM%_zLq&PsEDsGEDZfBo8cu)5fQcWZCbNn)`FRaEbh$jyZ4mNm0> zUvhe5%V^MMqXpCEqfC_#;%i>@`Qoij{-04)1~DY<4#EMun9`IXV#yTy2C=fXQZ4o4 zBOaT+(E|oN=|l6VQV1Uf;eGKauer_#bGa);+{l7gcKX@6_+}+3(|aoAv&+O|95yD) zdE|s^t}PvE8iXv$rI0x^_r302`(?Es$rQ7s6}WOcv&_!g##Pm_?z{^IKUymge2KF1 zI4i!nn_RpB*E{l`m1tP**(uJxTy9^C{rYWib3=_$Q}Eb}9hq=@OZ)Rr{OjUV8B%)i z=a)GKO%E~!4dV)&*lVOTdxi5YMZ9z0HnGk+5w)C+-TE5O38ND;F2DwShj5@=)RWbK zUODH7-;kH2gyt5ih<5%GyHKuKU)QdJ<;F6^Q9-`)liN!L*)zM2BKn1F;FV9tHX2;m zy}S%jy&Px;>7vjsJU>+SwDvYAaA?CIc=&BoChydt);d;b8$NL~T79m2D(qn`yH^n9c;Xp!d`C6R%ppzNSAvX6s=eH9 zvt|wTR#%s)!m8C)jOhFCHaRjrc}|ZMJIc*1o9+|8&KLA0tcd9y^gl@w+_>8W>9ZJZ zMGxX^xvnmjJqNp4{MmI>1?h{zo)SvYAA0s%i{yDldNjlxVmcxLaLyoG-oZOhwYgx zgg(xa{5m)bWq13E@v9R8%E`-{CO}n5g@;K$V2`Cw@JeT`RS` zBg=IGjn~sM^f?QFN$w;X^P=2sAdqhwkH+NH3gB@+&forpr`bu{oUW1GRmzE(dJ|@$ ztG-;``dB@%CP9)Drp`kuQHguzRk=DYAD5N(mm@<{RyoJ?(xZUYI(|BozdgOncCHiU z?s}Sjw^OtEbE=DOc;Nlb2)^lO#UGI~`tRuPCFNF!vc3xrNV36{{OipCi8{lk48>Zt z&N71o2f`0WhpdI}70TVHR@?L!Kh%)L{3xL~!y>Ipcpp_Uvh>Xy)|nd|aZYg&7jn z$ZBq3#fl!q$?#CpEw)rE-R@tAV5+MW!u%alIm+ged0zGdW$jw^oQ8PEX$Aj1;l&6; z1;H-#qV~xr#_IFTN>@#>-@g<_&v|`SehuMmW%$;es2omlWj}O0T|#y_SM!8S*S6Gz z&wQ61L&acx_CNRc&$Af*68tjo9AFPeO|L!x3Kw=cW2p&)!{1Tf#2Vne%1Lp3wk4a z?nxcRP@J5b;ECJK>KGMuUn#n#|DJBJKp|Rr_1~r98Jz6i7vV=+H()mXGK?m}`(fAlB|0#!a?(k*Dg zBY4gC4^HVJyAV{mhB&#ze{uJOlLglMOAT!}f((sPyMcj=$OM(A@FD&lS}b%hG#5q%p1;GiEinzJADki~fNN8c6S-i0F%Gr@!N^G|V?ZlJ4RdPp{ip z=k=NOO#E6J?_@iv=`F%Cow;^(&D zG|HWMe4f%=qS3$iOXM96?Sd6Zehd?9jWGZ<5S6umR@l{gfrDK>S1hdzR_t&0^XjIm zMjoG=O;Y6$so$+H=1udPgpYEk}h1M_hE;gg^PNGE(ocH)Rvpeg-~ z1x&cAfQdY-rEs0f(zY#FI5YRX?nSHH56%okMt;S~?^PQ-#U-Ro(i)N5G{AqMa+X=4 z%Hb3_4l4mx*Km5LX`I86L9?2Eu)`^Nmpd}N|A~^cD;Px<%^?qx=}YoQ#gZA4<7>RR zqUOJewaem0!;|n{!B0&~k;v>Tk3AuTEm)^kh~(oZkw z32_g~cd<(F>!T%+#a0opwZYmgW2&&Sl{NK&w%G13Mu-6mynH|%5uy=or}D0)W+1@I z2fDN&Oxoe*0uO;9h+Tt`Vyd(_{0W0M1>&@#}_Oi_}`S`n8`2EMM0&Q8?gi z)vSr!b;ue`R5iyYzhHFD8S!Yob-tIbZc1fC?kq}>mlfFPR%)ZNY`{5?tr%;^Ef&Em z#BxtI12c~e@>1?G%WD@3NMkZdMbXv|a{N-jfw`?A)0d04v#TJc4AftvfBikHRYTK= zP8fQ6yP^L;gGSr1XQFRc&n82t!%&y6hH9^XDDUr=W<2k0>h6Lenl@(>s+ok#)$cZM$Dm@ zApupV-HEEhPwcbUhiKypiHu@h-7y;(c8&HKh8o`lE9$H$@_I(n16(XQ=VT`lS%lr z4QDGc>q{>DX{20Xd|Yy2pkf{s?TflnxkMkiF{ASur;tI5Epinz!^8_0A6 z*PaKvp7kfrrWvTD?AZz7ocpZN&x2BBmokpj^oG7Zu3pc>34N&GU7yxM*1@`qu8xYgjy&nLYh7_hrP}zh?uh z7lATBIysjH)jS$Vt6Lj*Xq*>Q9jV+ zvDhjRzR`4PkBdbY)h;(Ur@<+CQd#zMy@uuo>F&15FjbuUK4a!Nc;oIgXQ9!ol2a4A zpQBK;Z_DrCy1ufySjt^FnutcZiICM`o$v0>y*T{$vJC|p-EW(cZ|HAXj3sGxup(L; zkcfw#%@^9h$@g8U%;Wl6wKym-8dA?ctw~4SoK}zisvlu8b87 zJ(N`*a^n^=h||$%^NfHlf7g?twM{Gx&X4^%9j`^G^8eXpxV$CN!vfDIoxk#v2M;fg zc6g;=>|&0>UC*%0p#;YyaHJ*&`hhJby}nwQq`oU|;qC1Ha6lwJZ+GrobN-VSsmm9C z7(=~7i+sY7EQe?o;W-0ENPQ>YyCo8CPb>p{-_TAfcSL8l|^IJV#^spXnWHO)JCeD(7y zb%_EWtgX&SBH#Ef#CR0(dAodzUv9@|Z$z4zdYIaIS=v=fIAX~y*E+rh$|}FC{5%$) zUkmNHi{=9GG5$*fVk?e1zBy7FZs7Jeo?sx~*rTR2uqr36)y zJ;xvVj`l<|Xd_;bTB^SsgX<4qOQ}b*3b%U2eOPWE5^%ov@HbugS>~!+fNZMQYsGh4 z*{e#hKrICk4ib#$qu{mcT&Hm&$5!P~J!ZtKSB`2&C#B)AjeKn3G?^w$)rP8XLYUT3 z{&*7GsvZq`&(yd$?p4-Nej0yii^k9Ml&Q?N@;?o6Qsu7}bel{wWw#$#;Y`3WBM6sd z6CPs{ul~LGL-*Y#4QrPEll!~aSnSfU#oS5rD)mhOfh4>xxskEdhrd%A+Rj-YSE6|= zkVi_@{`FB%GJm~E1CQ*gw*m!Lyf?gz#LB(HIX`jb$>pC* zlEc6Ij83%eua^;uuahP*RvEOl@+XPrW8Qla)OlpPe!-H#b(Gq+%)lU?-e|*Qw1Y!4 z=3S_wQi!AA#bvFY9pN&x93v#jBHp6X2c%yqp~EnCQTL*HGioal*+1KbHDREFpp&)* zOj0~W81L*EkHZtUR=v)`kCC;LcaPz>|DbXI4XynLjr#|F`+p#I|35VUcU13xBY&>f zJ0^8u@qRC#MgI$a1IGf5i*?10?W>b_Vdc>jr@LVW*WxYWwfyh^bnn>YGv$+NuqPIs zz^pgZ|D;;2Y+dQy%|!oiivZi5voM?F_-0+$hVG+!NME|TAZd@6RIJhu0E;7dtMPS{ z;hreIhKr;DPuVHulK}p>@aW}nXCot11%mf=v^+_)qBkn@$^yWjb(0T$&Hnx#kZAzy zGjEeB{W7Nq^EUuyy3ZS=)k;w}sl(z%11Hb=9Eck!=-IRS0!S*i4skRFkmrbNCm=|K zN5hJ_e*ifCHkTMceheP|nn9@+2G>-!PRwuvu(DUs+Ha2rGcEgH7QuS)=DpKipBkN5 z+H(MiI6!12Ekwp`VwBfT$^WC?UNQ)PP*H5K{H%L%_AXL3K@eYP_ffD9EndOM1%PF- zKIE2XWOf-xs!mihZad_mUAz;-Gze@hu14Ee(U2hbcn;*B1GTbZRM_NQ;;)^}eC(BN z6EtA~`LHjfWJ_SA`<-P1@K>bF;EPh){80G!=N<(pgVKbv#eg=BBHm(C=SHSK>k`@( z%`fV7%{&aO0=$YHQ(GJ*z?N%DwRr|47Qm!CMDKN0xAETzS&O|6*w(05xhb8})SCbt zelM~%O_*DMnozZ2{uT0=P04#T;Kmv|2xJCeXKlo;w$!yvs-Wn0044jlqb2go`Mp6R z&95wZ!699`aS|pD?4qN{z;oh<4ZAuIj>3v6feHzoTtK@-u9^#TQ9XRxrMLxxcj6e* z<{#o^KqM3r+%X@Q1o}@ega8ep;x<77(M9Ee8nip9r|aHSulrS5G*kS0@&W7A zE*+Bq$m_a6JgN+YZ3H0c!GnJkmi?QEpTmzp z_fuxxSNWHiUO)_rXE|{uuGAdp83=a-bI(Qb&dKhefPUHWM5$N@Z%+qroA?*U%K#FQ neIp#0gPLx?ar`>0c=u@SrLH`gw6h1i1nKD--7UWJ`1yYUL*$-O literal 0 HcmV?d00001 diff --git a/LogoDesins/logotype1blue.svg b/LogoDesins/logotype1blue.svg new file mode 100644 index 000000000..2cd790cd0 --- /dev/null +++ b/LogoDesins/logotype1blue.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/LogoDesins/logotype1orange.png b/LogoDesins/logotype1orange.png new file mode 100644 index 0000000000000000000000000000000000000000..87a7060586197a8e7adf0221e1efe8f7d7bd6e05 GIT binary patch literal 7509 zcmaiZcT`hbw{O&=s5uk?gVLj*bQA>XDhP-OD!m0zq(dM;s0nfqP*hr!CIm!!2}lVc zl%TXI!5|0$q=OM@p%X%Vn{(fI-+gbqG43DPJA3W9W?OU4wbyUPJ}}m2Kh1v{1Ol-e z+_`N60v$yF|G%C*0bK9BdU6W5o$|e7?GFNhxetFwdPl=|K_DSEgWI>vf`2ZK4kL&4 z8ah@kTayaaxX_gdvUtJKtH-@w6yLme+(qh&**~+VkD7DEvZs}Z_H_vP+(U|5OrZZs zRlfMDC8F)oiQNNQ?=}Xd#`Vc@*)hHuwXRodr*_;G{-X9B}^?N~?a+7es zG~2uXqbY9|c;P>L1O$Roo0kJ!CKp4y2_tvjvHvc0eF#krchs(;;KoWGs&Pa}_b(8LYbu`8=c14@WAOne2v%YJ^YhrcW|mx_0>}2vm4}>aN%SdEl9-6Q!28= zjI1z#{WaWEUL&?27;@)L2y9?~&qJCb&9>t;<}|%WH5}mG4@2Dd6Gc%>Mq)yo#i?pm=8xb{X9$c(@=yi2SWwylZ9r zOOKUejz5tKaqSo8b{lE|A1?mbgX#wj>IyXqhKlb;CEzFhK%mU{pd+Xb3nm}FS-tAi z@z`Avc{UKp_-6W0@qEmUVZC05XRMN?R#3RW)9Yqq*oK@xfKwl6k5ql`-mo?qr}?eL z$Qod*(i#eZ_=>1~J8KNPwj3h-HV9je)^guubtv1z3p`xM08@GW;IY-n@i`kVra`aB zGnNN$@1_ZGyP8%JgW2bWl>v)M=5hsZT6pK8ES$%kOJx#T?Mklv8<|262eBUW`9{e; zJ7)RDvSyy-tKX*FE=eXI7-9gyUXEZnvwV7Y4SG_ABnf!owkalJs-Wv+&4C+QZJdUDWKOEE%1fEYG zmQ>L;An7BxfVI2%;u!D@HfIr5z16iF1XvtYm zh<>)X_%qgAI)xL^q(3&L4q#ZN^3Gs8=zhfT#;x9;HuHc!ClRv8>ta{Se{hP2mtCG+ zl8H~T7L1bsN~`F#&w+)I0Bn8z11)=oeQ&@O2b?6ZRfzue8Q+$?poT=|qZ;iVSK9#Q zH$uz|?I8M2bezwO(q3!=<`R$`&sb9V!Jug7uLmpzEgb{2forF2U67`v$m+6;yQDkR zefGz%3t=I{nkkCvS*gfx&-RvjrB;9ZBy_ zaE}yVIy%Xz!u|=P26u-~23UNJU!0$N;efB4PU{!?Q^xn$sx?Nxzql#NJdoXRcQL6y!BW5PGPu-~@p4YD z!gi_*gQal=+t~p{Cde~7Q{12h>|4$`6PtHQDy=%k;dY5u_C@vksb|NWQZZUX=#*=` z1%!>x^)FoY{idW#bRw z2MVupYjSqNo-mz?Hk`V%Y%MV^kUOqBR4l=1YT-zum*l6#dJ7;mE=0N5tT3@2=NQ8o z%v64ntN{;4I}eDyDII4dB7NFd9ww2^B7L+dOoR=FY=xhqkwjQ1mmaQ9@$C$+7x{5Qr<<~~FkTXgH(xM1(Q^=GQYv51jVc$DJ?W=% z^Zo`i^x9}CM%k`nUFMmXJ)q&;O()T4#7>H4uELr^#JYL-y*AZR-5W7e{YCg=$WaqSJPCfp*0ZrS8d3f ztLEY9f?NKljxfR^8r)d98bV>3GN1O)6A3r&)~5zkuWeYfUjJnOtj{+huW}QML&PPM zv0ooLYcv*_3Uid*hXbW;bko5m1M4AKTQc;>o3HaeO@--o`+wFWaOIfjUJaCyJ!SO1`e8P%cfp-v-b=BIy}~T(q}pHgOjZlN!r#vX7B*%olI9Emneh!*Io#i3Nc&a&$(EmMx4YulHj2=ohVw zd34{_p5LEPdyaYkf-?M&RV#TjtN8AZfp7HvCZR4%9p)bvTKm! zlKWZa`)K00*yvIi5vO!msXM3KaN7{tI_y5HCEL(NOSy&aA}lRp`TdLS(N8_V;?_#GG|X+x zf<@$jh#PY%6K}&l7$`0U)2Hbs+2bS~ml?cUQb<+3Q{j#djdxvdUfJmuJ%ZPDFyl*}-C2&_&`gG&P5|PG}2jKn@ ze#^({3F&zS^W`1(R4FimhO9SJmu`HXSGYMaF~>{3wDH{AFd;hW!}aP{JhMlGLU@el zyoeslD#97>&~DCMbj9c^Nx!XcYRc2dH65&x(*ssI-+G{M*RU-4D4v=&x=VP-#lrYz z0%bC2!FMdHgnxJG)(g+|P#e!ELqf@t>{{8g7#+$}S)Q+*H7)($pG~aplxOf`{LNle zm;b>39M77OC8&8tBcpQvxP<(KP5zWh!?zyWESYvX2W!!p+PS4-%zEnO4rN&D4&)eJ zEIB9mC4XNfZy*g@*ivlOWuhq4;ZEgXSl+KRd0N}kgjS0 zftg=}J1M4B^n&7B=|{fb_55JIm2egnp4~J05>0=a6WY;XWXE9flUM3VTyVngd-Lzw z%%s|m_af_))}PBx5NjiAU{>ovL|MmJ-+Mxxt)l{*gC9=2^iH-veZ`p66(vuasE*;c zSTFYjyVoG&AFRg%2vdU*fwMpPXSSy7nO1cQ@&rwKQ}TfeqNbKc?6euj>SSW;@VgAP zy)u+gDVlS!-I2t9ciS|e@?Wi%%uLAJXLshWVkPl=_p zx)^y!p*`H<{8=RHZxrb0>__|zHJL!&d(+-Skco%XHvIVWy?d29c}dvjL(_U)riR3L zMZj$E5ffW7yoA8)eKu}auV(tZDv`Hw$f$o388gOp7i{>@(7hDubj3loO69ado9dWT zO`DKU@5<0}?5c1h!OjJ-{`X zc+9D|m9k?BqI5@1)Kl18uMSvd@FITm9-ajO(-PMSyIIKXVc?6# zf|Xdg;)mWFd?B!}^@J*@-LDhN*l<0Y5ZCbJz&2n#od4&`W3f23Wpjomk0MpnF1u0< z?v-hHGE-@9)xA4i&GJ*7g;wiEzw1~7_W9!v@qyTsMp4Ciz2!YrW>svfq27?6f`8o@ zPqgCTjUujxyeEK)TJ#>ij807p*Lgbgs&%WOWW?;_xU8|^hp9@$0PwZf;7qZ9-{cV; zmJfA&JoKn!?z!v6+Y0sTRmsYv9pubE1FZ5N3VctlI2egHS>7BKy_{Dhy;1CCU3q$X zEXQv)yVC&f>z=H*cW$C#Xc#doPnN4wsc;nu8CXS6BK^&T+7Zb9NwE`O7z{zdZZtZ?DI=U zp4x{RaRk4;cG|5=Y9X#d_N*!wW{FD??fGc_)9{V; z3qE3d&frZs%{tK_WqXF+>r~I-ww#4L{YG&}ld6$=V4EMGRDa8OB0KgjjoWDyI4Voo=^3^Z(p*hQzG&FwO(w)Y$G#k&wDmhd8RwO62 zswz!&eV)uFIlC619(QYL(!*c{&}>68o}zsUL5bX{1OR}K?R+hjl#S(GL7#57wz4r=6bht&qo2-wkb?w-vgYvNJfgCKKNQoCBzZTuiq~?@8A2 zK@P`}7@}d0q#WfX>dRCSV+CvQ2TIkLT`ZqP0QG~Lddb5_WaPuz)}N5`259)~&5!a) za`PR;zUo`4Mz#gNsG-3Hn{@8q9T*1ckMU?Amg88kz~23LwJUy4U#|G!t5?pDYQnQD ziA>n5mkh!f$$gQe$@S|a)j?o%B5*%c-~PGs{O=w|(%qB3MYGOzce-<42R@FBGb+0G zmKjmkI2f0=Np2gJ%0{Yzx7rE=d(X>T%8$3S)f}5ym;1C9{-<)?rrt%4vqVZ~1lO;t z>%in_F1-v{(`}M>AeZldCqf?EN}WgQgS5GHYn}|Tk3A=ES&VgY$p)%N zA7==*>@y1Ky0fuyI$kkKmTVVzE)4(?l#$;AH-9Cs(tS(*zFX|sX_SI$Obw59M+26<$b&5o!PVG;Oqb#Oec4YRHEbiFBe2~1& zWR;2y%__T0h%`ft^0b?0#`i<{EV5-h|KQH4W;Qru zou;fT@7#z>%_!d1?5~Hq;VZ>W(}U zs!?SkV)GqH#!dZ%xsKRXXPcLiGv=bx7tdtfW;jjT_(TI(V97zeWkX_3%}Q?d=_SgC zwFmQUF$V3&0(Ch3Jq?@$Y%wKaVUjdN?z(wn{C60ZvsEUZCS|pIeVq*`i=nmoSN0KG zo8F0~c~wdNwVgT`%FYe88}j+K+u9DcCt z#va78)X?WzO`9@_>t7l9xtHKJx%VIHS>4%?yV_E(9d^3(Pm07^phY`V(7(y#Y=UQI z;Cs8VuQ*#Ip~}V;VHUcF2aeYZGZ2WNoU~R-@yKNe?9TS}SGntnj6@&-0|m41{#ADa z4ZdX|KdNFMHYZ~n(*VNy;&jZ>y+EWK&(-zfGH8@i@3}pETEjnX`SaDE~#&l z&?#W@QnSUFLXgi50%|eThA22kR#tVk?ejr<PziX?!_e< z^O4@%b_5^6o_(W}2{Q}N?-Kpa#q8@l)`mDSlf2|vOpFns{x^+fn1 zQ$qKVzv>oM{n4uRPD5wR?Dio(eVVxV=xXmuJ&YCsc9{{cf2r-Wdi;*jCHAK>snv=isV^Q}pEdyv^SHM~k$1$k5X3YwU*=EAOVHvwNep%GOIJ z&PZu@D>7AXQ~f!+Ace6RNx50EQ@y%^kkc9})0}wQ@_UV{oPp%LLF~`6Kcy{*n&yt| zg&Z^Li3h#mu(VjhDHPW$c{(*Sn-&+U%2%vtO2U*kt2C0am%Q8b8$0sBM_E2&r7l^o zt*<^xeUh9~gDWqGikD-I{+9UJGgX`8th<>$yAdr+pf=Q(G+~*G^}fU6%6fj;eg_K6 zG7IzNv*no63G|+L=;GATIw0WY2GzoIP%=EQQkDKI1k}UA*9)Z!UbMwkXffqilLHC8 zbIG=>Y7UHL*b60V1(4z&D6P1_jEmTZ0EO>4nXfW)uOK+ z!fr<{9O7>O1E%&b4EGBcX(RDaO1BYsrZ5c`6gxf8|>4OIQSn?`@Ko9WBmy}V7HMNX(xfp_? z0C+1I1VE7WyiH z34kuC&+Bl~2A0->qj%m#E7(&zn#3{Xl6QeQ1|-?dorkPoV(iSMw>rbyAOcV-s?P3y z?>JCBQG)WWo@27IzMB%-05SWL#=ci70JD!uIbfcQ`UML}IVeOSe1KO-=mIuW)_sTu zv8N&5-Q7+-R22nA#OCQI+;9c@8P>jblmmnh6Jzocu&r=9)n}Zv7?T1hs54Fu)sz4j zTAKz7SWBoecQrI5$2+}lJv;%Lh|OY3obkabqN9}?YTe{5?t}AKGqcgG;{uKT4;|LbDegc9FAMHE^~L}QHC%2D>49t z){Ji|uw`VhB@<{K2#aqZrwjou0Qyh4k}Bate=OhAs$m`6Fl`2~?$FLWP6Qwezky5( zR{?cb#d>3)hae4wU+#)~dq3PUyN3Yyamo8zF~9-$ybgQidgYZMs{4L|J{?vFKJ3XX z%e7f2g5CApMoHao=>Stuh0cg^+Pw5@{LtL$+&d&NV*l?+O{ZSI!<X!D@*8zto@`-#=uFEC zU2(EqcqMzr=a%8f3jo)X2zum5Ah_ZZnNn#E^o&H?%z1xrcMhbMh5=0#XCS||?br{+ zmd~yDF*|L?X}kdEn=eY`yNqPIgw*Zh|4VlHq$oj1p1Bes;#w+mNZ_g3wUONYxXEw# zOl{}ULpVO6W#miCNPCvgqyM5 + + + + + + + + + + + + + + + + + diff --git a/LogoDesins/logotype2black.png b/LogoDesins/logotype2black.png new file mode 100644 index 0000000000000000000000000000000000000000..b5929b89a8e9be56a8c75ce0a109a822d0482c92 GIT binary patch literal 4357 zcma)=XHe5y^T&S>mC(x#B?hDjNFX4+NRbj+1c8ufFdzsB0@4Md6a$w~LRXp;ktoH$ zrKx~4ks=)~BE2ghy#y&z<``GR^j7EN zB2W@jv1O?7Sqn+o*E8+hd^b6)L%q)?Ny$=$s>5cOWJ>JT*$vdvH{rsJ9}kOLJIM%P zyNyWAH_*gF$@V4Aq-WH84X%RkVUczmx&(lW(-_$@&zTFcO#R56#MgL{cn$CcE{jy~ za7G#~BG;NWmqg`N0eZj|HuZ>I$PT9uH^^22aHBq>G=~k~2K77*j3&!1ur`p4YRl+m zid8pC_FJY}IJfw$(Lb|h^sqRGD9upmH%0e4(Ge_ks=F;A6O_$dBib4i_5L-~S5 z0Yoq5PW1g7E+KQJQ@|!4dIwZ$`Qu`Z-zY9@3BVf#~BB(%qiGahp3=^dww%{@fr zl}WBGqBIg7FWu6~wbT{r@imi#;l#(F`EQ-$)h1A6U3i~ML!BFR;E&Qi%0Wx|9`NGi zb>WYCU^jqugEDmlG#3)cJZmKqtX5$YsHB$encN5;CD(n-#|auroB^zbr7YO3D7{G( z)2SH;oMmwv_%;0kESX{g7Hos}@JaqI@Yqom>+;EbG@V~AFa0?S^V8Xk3&}J`9}}5Z zHR&%{6gU}yBMQg638BFBu)ZYw30;_oSd ze5H-Gz%9CNpYbICC%AQ3i{J#De*}|swdtx!d$op(b}Kb(PUDFzn0TSf@_DLPg;QBs z`ELfvXqiW%$Xv?zPnO#+-W(Tuhs;7}n|^RXHIH}llW4lM z{4Bo?aFOHThbga8YOmataLv7r@}fRHdyfhlS-DH3Om!F3iBZC0*&BHs{jPkf#CR2|wjjpT9^8#(Nq{s5}R4z}`j=1Wib0vcs2X4+&PcD1P&r195=CV2C}Z2chCFMB#h{(d~NPl(6P0GyoS}3>@r?XdV1sn`}Ns{!!K%S z4;3ejhxgsClBSEVUkZK`auOisVN&zv+W=JMtFl&nlBwnb?9HI*UXbooq(k|!dra+X z!5A~=iKyotv%r3K7fk$^z|)jPuRQm?RK^l4-;-pY>3FfW)b69978fdsWImqxC-}}j z5}YR#j^@yXgL5I_=1jU0XN8l)I8ZwO9R8cYa7iH9*NJhuPF(_bS^*t2^L?17l%Z0pTPZ{%J zoVkwV;F$O#+s9j z!%;TXZ-SZ~q|m=x+597V+tI666ytiW!7=>jxx7Vw$)D{Z*0e|AwFFRVp(UA37m<|W zmvHRtyDhf-yW+dt&t^vf1AUP8wAjs5+_!<2yXkbe(5rC&o=~U;)McPr$pxIZsEMIIO74D50B!1H)2JDkdSfgIU?X1g zw?Op=6e=duV%-bp3SGY}fT$T%D#MK6>DaO7%0=TbN|iz1V5f)JuOBt|J_02$hr>5` z_XYilRwSW+gtjA8XA^-(XH#r<0jUGV`QbnH0<*ymdywa1Zy`QhT7 zr_Vf?gc2}_YrirT@Vmaz1YV?GYw%p5>pkH?&CEa1S&ACKrWH0AYid?6r%YM_?ccw{ zp9?W$PnmG|-P#D_7hUW)m(p`82!fJ+-6}k(o?c98=vZ~knDDgMDQr-9>!My>{LfFF z|G1;ANR+@fD=*@7-di%JTv>pz;V9SP=Lrm(#}lV{K4r*k^p}dauO6Tws4r@yYjC6M z@qCRLhGG8&gnz*Y0sJ4p`4{=Wv;Uu`d(CL1ljYFQ)L6v$x&CO|wgAYZ;4*-}+EE0vjy{?R%?i!(yQF(7LYp8ZjOR1U!qHh8(}eP% zX0=e3Yn;Xi&l$){OCAAc*RX|0hB?f^L@LVaX1@d55vQ2|)(@Bf5d=r_-LDzkV0d!J z>0xsz-2$s8&`?MX=oMI5nmA4#u`%d@{%y*9lOKV<8H{+`*qSF zB2n55KGt4d7UWQ@vaEp<$*y<@*T1QjD&B^p#j#ctEivNL(5q6B3HQ(MS(kd&J!9d- zKaKXc?Wj&DX4+d~*^UUr`bnHIBiXmplt ztZ+)KNu}bSXckL0h5{+*!>SE7K1mC5?gFe0aS~F|FFe~{0QsKi$zOpy9;8J?8P?jW ziUkTGN&*sX)YjE82PITyrjJQqC${4_4$Wq-*SyL^$Er+&`-7R%@}Mj^1~9arw8gZR zdtV+$vi+*h8P=bl)QR|1C)uD3S0gOK!rA3qo{)GOmv+-eg%;z;kW6lYb=Xh4HLy$bhTj3_9=HU6yhatSa&XM}VNb@6s^rYY|W9CUSGf1x5h zzSDaUvQ_Nb?gjgLy*9T| zh6RD4_Z9w~+iWw?Mm_ynr#rZ2FDx&b&<4(tjF@~YIUy0QtJCvnSZsw=a!9QRZ1FX9 zeDy}1=bgATo~aMZTv}^fK7Qadb^)z-OdYTT`_a8T=_!S-owNrq4_if1#qFliZOBV~ z-2O?Cd!23Si`TCAveznItKTIqyUosTP;00-XDU^Tc)68R59!Y)hE=*T*eK3QtNsH9 zch&Q8EB(o~(rx&Mj()AjVV6&4vF(GX>7y{dVQvMw;7HT$rr!6aZ@4Sp==2@%z>(;Z-*2g94T-mmiPKP@I^g1l>N2MIK#D;A!1C zw8`I)+;z8zQkq`9KUoQiBpEytJeZS3>#BDQ#`E~!FJ*qH^Y>P*Ol{BtW&W9Bdv^bn zf0o(^iJjqP&uHCQkI{xT=;!x=kYI0h<&KLDXxs%M1seWxo6iTQE zlk?{?4?{M{74Ew+fwy*wBX@Y3vxCi8S~=yQ=54GV0vteB>Pvt;2T;~uNl@7yH{-#v1L=|t8Sfj=;dA7 zv*%YWYkf4eNlE;&>ToE`weF{P^nL)0X^*~Q<5_;^INzbcH)geI+W)=uQE`v| z{1185+ePNqjbrn}x1I$JTH11WbNRZ547iP&p33n}yh&KjEk#^0)xv{ubFZ~%vvFYj zdn$f4>)L&@+sf)g4@^$35BdbQ_cu8`yuft%Dmltl<=dcc)(b~T zSt?ACh|6lNPa{Bl&&^}s z3*UW4Ol(-6oI5E{!K~@FQaHX;Wu;G#O_qN5CODIshSp*Hi-J@6K(VK z!&aM#Ak^6gXC|*4_ZLGWkoDwwKv~UlxORW5{DjtPOB7qJy}$JGJU*iy2(= zNqBUvt||KNRGY~-G^RW|(P$56NTojCNgL1jV_KnN{M;{$?TKK5Z>cA#%}f0BUjs1K Lzm6=?wF~<{XfyCl literal 0 HcmV?d00001 diff --git a/LogoDesins/logotype2black.svg b/LogoDesins/logotype2black.svg new file mode 100644 index 000000000..8f2307fe1 --- /dev/null +++ b/LogoDesins/logotype2black.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + diff --git a/LogoDesins/logotype2blue.png b/LogoDesins/logotype2blue.png new file mode 100644 index 0000000000000000000000000000000000000000..b73257ca7ec9a092ea829c2a24c5e72a214ad009 GIT binary patch literal 4403 zcmb7|XH=8R*2lv^iVy_pT`2)VPeeiyK}aYGQUXX3L^_BXdanYZBfSXGL!|c-Y0?fs zdXaKOsgWW@fl#E0_{MWT+;u=ZQBm&|zZWWdHyGOnSO- zG^Kw>X+P*`DbHD5BN<9}*+bXT8vtNr{oSZ07sAc~0G2g9_#M-L*=?NRz1K*-*l?M# z3=GYnO=Rm0=VgWw0f<7!vlJ;7^Y<-(cn)mzapaEV`dZ%+SJmb0-s2;e$O(rhT+*cK zTIU~kdjrz=+vIzv8D^mQ`E%yfFA)7;ZrY0!e|(^903(6Lp7x=PA}8zXWZf5zI24q8EsXyn*3wLv%% z#tw7h+1EMkW#bPurcCCMx^EoajT73O>Hq;ut4#ep=~t1)`9O!X&uzsy-Mc!xRK z)%rz!PKYy5?N}?w3_8gN22LHNc2xLmWb$q1uFvP65T>k`3u*7J@!{l*cVpOTGy&ar zL)bGz6PjNbN;Qk=9q?8fzMJ&*bRO4eFIw~;%i^9&ziu=D0?rlmgBRYE^7;jp80CT*dP?ygm1!PY2grr7 z%rbu)2Che_+E{cfD8e#EbGqSb$tl+1D{A_!?7N0Sp+N0zOh9IP z;n5YL{6`M(x8o`hR?9rs;{q-~hWG9THnNM6I-HiI-E-4RI7gtX)4TVL)vXn?2TK*C zyf+=CUvD6A0=|r-VD6J_gEi*;dsFeE?ZJMY$h6+d&6ek^l7T7@2+^h~1A9YH$H?F@ zBkjWq&G>uO?}h^nyl+F|58X;q*M@u%n(ZR9r2HmNZ%N>Jab`n^i>{ge`Vm-i@#B_t z=s3@kVFLs85}tij(QiU^^U82mMSdWz=8~G$psssy%QuY`&g76+e&(Rgmm)uZG6Vw{ z4@vcMUZM9GuTc->;Wgsg8@76y(P9;<{-I%wVN9Sc;45BNIJ0p)HH(Z|A75iLrmgm& z=W^jLnxGhxK8e+Oe6E@eJ3QNyj#j2|99lvOlIr#JYKv1vgQHyi^9orD*@d4Gokh)h zCOtJJXoNDKu^{iz7hjJ?vuJ|p3)!QM82*dd%WpN$jN(Ql$PfuIKp0O+M{2BmDzb7nGvF3?Nk`f^={oS0$~DPy=pW=-yICnfV@5;JIA< zUK<;4H;V#{b6}B9Cqk!v1=V-Jyv$jSueZ6je#BKlPx}l9VbV=kid~_mXN8~2lUZaw zH&CED6f;Gy-P>o1J*6$)&?+;<(hb6#A0v*`m>Mm#V zy(n$|9gI-|x{wt={wZu@1GGq$+W^OX&ZuB9fjccQ3v^8f#H*mRl}rwWP0^qS(4J9s z;TR`$}CZItz%xZ1G9KD9HKUGzACbs@*(zR(`Ed_@?>#9r-;>6kxcx) z(PphY8Q0WNYPp{bi4a#5DK3*VJrf6pRE`>U(Nl+W(O&R(+mcvi|JgyYrBtRjeB|m< zeF6%L#9hqOWtVxE7&$SMg6Fh~)4l58IP@wstB7E(+XN1=j$IShw*YG2(mqCtTeafcZDt zOyNO5cca~`JCRT=NDrZ|OQVXU&uOPAx2B?y^n)gXjrO9%0cruT9s_1BbMJ`Gcu=+2 zk#<#5VJ(2Cp9sKL22ACGfU3C{7~MsZ?xKc}1i~pvbjgCZM9s}|v5vF;GO^UEg_exk zPj0Od%35VgDUkcD@7WaMAYvDPFEEO-OA#;z3QfZ>;MC$qU9{A*8iYj;xqL5VWmJBf zBjQtQjtA4!OJOTB-g>Z-$>WgPmQOJoZZWaG@e|V+oa6*l5imO>UEDBJp1Sw!q_ObR2 z$?ZEFkndOaA?T^TGZalX1LfE zK41T3U1=A&r~#gZFnmRBJ=O-d!qCf*!N`ZOp+p%p}8 zsnt;0rf#8nu;TY7NsvPsp21;0726kgz%O!$nyN1|C-NtO$inCRH#RKsovb_`9)pk* z(cCIoNrz3802}!j1v6+v&WsCG9!7 zLg+$W?9fxpyU>*H>;9mcW0dOpd`8d8`k{Dn7-&YpqbziRv-WRUD{LU}P;MD9<7wc7 z7(BZtEm*x$pjGHAzfk)89~Q$KuatWzdYs9phF1Eb5q*D{sWw4sGmei)5Z~bPhkh(4 zWp2o6rJWko+gvN^N|Iw&S-$QttV?QFZMRkxmr;_rUlsKOX;SpID61g z{HKo0{3FrN6S9au9k~NR=<=j*Ft>G~#%G{))wp;_##a+zV2HR#h{y6eKkWtVZgDOp zBXCBqIuUmq6%Hhh!JleOl#j^Q*AaJI_(9s^V$O+00lR=cJCdp!%ovUXw2ZfV?T+<73}q8h?P|Hb``jn0M1swE^R#);<$7Vg1eFDyZ*y|Po*c2N2&V61sxy*RrYQ9` zjiJYop^s%UI8+=roATl-V*<7@N5sC)5r% z-aSb9rKr=`xhORzQ;>OkP4MjiD{UtQ=S$tc0OwJz>W}jGZFea|J>c}&p{&BJX;6m( zvKiwSWL>ge5J>D5FGg-JknO1-yaifqksuS1S8}7beWP9UC|vc3X3{wk{vdcH!DRO9 zH_>xjT{K2-u3!AwCStkAAfD-KS*#U%l0^TQ#$G|$bXcPF=3>@}{|-fs1Uh#zq8QHV zVaCo)WsccK8;pZ9KTUu5JSy$1Da;+co7d`mli$D4YbPBg>XOA3Lwi3qvMVXH^`tFu z?eF&X>d>cYS10*zqA2-^a=$J2Fzf=la(P8SZs({yW)r#pVI~yU7!!>&jK8K%p<%T; z035fn{Izcais@r<`w;)hC%ot8xXIXGT3wzMxgh(fnVa|_^U_}T9oZWyjjy?vWQ&hn z*!c!=1uaXGN_VbTm>#l<P zzwGVW#&NG@BC*X+u<|4hjO$NNY(*wj`AgK~ES0W`QR*%M)tx_Am3Jz2lh*hJ+2Vgu zN`*w|?$d9i$9p06vJgWz^Q?<~LE27#AzVNz8;0vMh;>FK+r_`3=*V>6(Dtg?bWNiQ z2w%JirE!*mBjOViYDV<}eW&(>qt|!pqmoC+a!zyKQ%yz~(~Yv6YEDL=WfD9F z!PUwUUGS8uH+%l4KbP!Ch8&WQDEaC>;37LeH~ZU@HUHnEn@P)!z1>hv8mT8ToGW$L w>s3EKlw!ym{~{(=DX5C-rX&4 + + + + + + + + + + + + + + + + + diff --git a/LogoDesins/logotype2orange.png b/LogoDesins/logotype2orange.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5ab676e44d17a465d5f657f9d04e89c0c01bf9 GIT binary patch literal 4368 zcma)Ac{r5c+aHN!F!qc!%V4Y_WG}n153(dFDiVV+mP{h+h|yr|OJfTWMKZROC1V+e zipW@FB-w?i-*o-nzrNS?ec$(wbIx<_=iHy?e(vXd&gZ@!jGc`cJF6fo003aOFgJ$N z#~yn7#llSQC(Z2?>BH$jb5|q)0ObDL7)Ga~jsO78cNWH%9K$Eq3Ww|$U}q9$2oqD+ zPVPJv2b#^m!7Pb6mXdIRSRVfJ&6X24D%TpC|-H#Hu}ra zUcK||>eJ#M$d-E|%egVqLLHk9m>JNnM?g9CuSS0w@2*ZIn6Ayj~;(ly2&gQGYO=)w?aW#GOQK({Q?Evv~K2NJ>OW}fiY4hjha!qkPMl!*ylI@Zuhi8u#U#D%Qd zMIj&+1tUCTb1-gzm8!kjVeL#2=PMtvNWk<3PH$A{T6DaHy2B_rY(}^_o6@n#M*>R4 zoaGl@b0RIuPURKNUpB0U6!Vu?USS4Ck6)w)Dky*nyst>~fS+Hvclz%Hzr>CNfJB;w zvr_DmGvaeBB=l$#O|u>!6>IagIvc>@b{kT`}JD?bHY{qiU*!xI+y`wAkIBcMeQvU>_nO@xA5X zNYd@z5u{$3Geoi-CsEH1`rH6ZG$rB^BFL{Ww(>&|4Rs&685$aMPq|E%^8_GZzWqs! zL)%BR8&TaNZ`=jdV%)wB@B2RbM(fYl>76c%{+ZfMltD#9qC{RIx=_J>y^AB}2bV;u zALk9wEOnUl}<*j0e=2xeC_ws^<2Vx5aMbzxMy$k@jw zuT)At(y=i$R*jKlU^I#7{D8hUa-%LV21?EeYT*X3*JiZl-4yr2@#C-MCK{T4hTJc! zY#;LNew4I#GgA7wr6=hE`{JP6kB0mITfoMb80 z#Bi-)U$TrePT#_QGvwy88JhC4-pYn48-A3CN=`o0r0qO|?ERThV`b1NYtjH}r4@!G zuE0L_wAna6EFyT9y@I=k&d%}gqKhv(Lpq8ikB?a+0l*#4sWU|VXYo_f!Sswv)YY_X z)MjG7k*^ld)Lb*dXm>qj7A;Av>}E)+5M2N@yhgOtc?QoD*5QpB==9M9qq|2sS(-cd zBKhAHoKRgvKtLP&<`#A3kEJ4GeNedsZUV2w!>;${)p6wuadxbRvP|Nc4>@6%Sjx}F z!8r|~ECk+vF)x1aD{?aCQHlTx;@>{}PUM|1y{)f?g+KQ47Fbw4)i)zCSukiaV4#Mb zmP}5BRZq>O0d&Rm@s+i$g$}IgkS;s#3rk)}bqsAx zO>ad&V11OFD0IkxK;4(=6+cN zXG5}Kx#~ghdZ&gv4rj;e@11k9>BY&7lw10iKN1&(koxQ}N_eFd(Ep9yjF~r{q#4EB z^uhwo$xh(C4Z=tHgx--fc4!8=s>@h4u7dE7|6I>#2?Wk+)Tf%&d&fzdfavhL<{c^v z4rRReS@8XfLc=ls3b}}LXlxM8K0d5@4iS?~t>oG?~v& zJQZ%va^yixZts8CwDYC=UIA!Uh}mpk&a^fNVMt+UtH%@-BgDkS*zjaAIXtnb$#F^A zH8;vf1%0EkOjxe!#^IbGg&b30xMXe*V-fM%P%KGh%2JPu-{xNwsuh8{DVkVcA)V)! z!wd6?6d*Fh2_XO@5n@LaSJ|A&Ci*F~xnC9oXo5Gm$TLdF^5^`h7PL3mjITW%B#H{h5)>LGs6 z%hoxQL>07zh69uOUNCnKQ%e7h3I9Tnxc?W8{^|UegYn#Bof--E+xI&)dI1%8nKLEG zAOKzIZs}!Q7nn!@&T2->YcRra-hf%H`c#ys&}C3u4#R|b;>9>i>O;rp06Kj(Pjspr z2ac)y6-6^;5(U&u12G zn4465U8(i_FHUzob!%qcu-r-|J{QL?vSSOB=gfne&|Z?)F_$BZJcUG~HCZn~1qU=w zOij?v#mhf@ZsPK8qiPeqpje;E7yX&|G>~yBM9m0*@V%Ru8Bt+&`f+vqH=2#%Ay%_HqW74^xLmTJ$+Hn{r zSdg2!`uO>o3E1#AzJfQ5dh#x>Rlg~=OoVF7o0L37ogdP?Eb(6TW*Jg_NQj=ILZ#Qa zWJ_EU38k1F#TE2EuXv$NK7z5_$4t3KzN!>lP7COG+fU)y5`|Hw(Xoh@16UPU_3w2T zqhF$pnh}ulxNScV!o8C$61;t0{Zj8)qy?-GEshm8AIrh1IIOn#@ zbYiOh#!P^f!Iy%2qcQ#|3|0&-fP~EjMi)jG;ce|0f2*%9ojl*Gqa?yO?aEG?zQb+{1HM$m{*VlI&7zE}Jt|9*9XKxkW~KE6)yXGYowL^LLggk@qj5 z5nB>}Js`-M6kO^bzGD{9r)`!b^&0SL^w;gZK)UjLHBIBiYH`ke3hsI~4-=f1u1`IE z*i#r1Dt7@gIbi4A;edV)8ujQs!^$4?nBrG>C22VY`T2wk$$7Hp2Wx;^p11tUeNi=R zB$KD>3xUM#+J)v8HHW*5rQGie29U`Or#4t;p$o*nIdvEHU6QR&&0R^Pg5&Dp34^v> zS8Zf>GI<&zp_*$J?@F&GUnHH|f|bEnJ|jlSMy5=b7ru(zq!=HD$ z5P2{a(A_RY7Sce%G|6Yl{)fXB(dO$!S8Tx_NP3>yP2gWrE4vA0`b1!DY#MPPYR%~?lM;CWX)A!x8saD+#xBo>?|{Uv4j zo{#dF(eDWRcUCguy{KNRiyyC#$p!^owog|+lRv&KRk!AG^Fs#pcjTqCkQ8B(eHmzO z%(CA{#qs;DGvu0IPMB?Z`%wh*8LbB0O_yI+fA?u^``~mt9Bv&dElf&d>V2P`%g+?X zT*lbFMCe62adkHNG(L`uEacYC7E#aqvt;-}2IZwUx!0E)>$M-ECf9$xrqNGFrL4h* z7d7FaA{6&jd6g=tG1G+WKmBKSctOX~$k% z{_R~lCb!M+7sls)A4wR>-To)i*19AsM(0*YcDK>mr1l=@>@kg+ zJ~H-*987VTT>UO}bj=)&AT^|cPL4h5jxXdE`eYA!B}=o%ip0!o*;noI=Z?0^=dOQ| zblcZKPs`}=?Rfc@4EorUWC2<%V_EtWa-oI+3lAo^{Jap&655uotAlc?vIb~MR zUH`*5)xEFttMhp0?VYAQqKTy01H|KY#&&wkIQM=JhJhi&`oz$x#}pgl3PZ;`IE^oi5b(=GgS* z<~j+LEM&Nq)Nc^|bn0(weGyyQvyCBk>wYCxH)hlM+Ya>Yjx7jpWl_d8e^SwF&49jo zn*QK0xw0g*@S`l3^==mQ+!b*-n7d<$zfJ$D@}b+IxX6~cZdlsdUGKOD&|mH#t)8~C zr=4<_lG7AolhfxK$MYEXEf@RpgdSwi{GopZM?y)c*CByv7D2@LlBk!X!ss(6BV~Qd z5Cuucb7P-wsBrLbxAI_Ls2vANuYJ{jx)5oy(-dRyas1Dz5t{>v`%UXK`Y#TEg^7*v Jb3@OE{{bKb05<>t literal 0 HcmV?d00001 diff --git a/LogoDesins/logotype2orange.svg b/LogoDesins/logotype2orange.svg new file mode 100644 index 000000000..bdd4c2d41 --- /dev/null +++ b/LogoDesins/logotype2orange.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index d918575e2..4cf79cb1d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) From 966cece43ef611843678e3be2739bdea0524407c Mon Sep 17 00:00:00 2001 From: danghai Date: Wed, 18 Jul 2018 12:21:28 -0700 Subject: [PATCH 092/302] Remove undesirable output on runnint tests Fixed #377 --- algorithms/backtrack/subsets.py | 5 ----- algorithms/backtrack/subsets_unique.py | 5 ----- algorithms/bfs/shortest_distance_from_all_buildings.py | 3 --- 3 files changed, 13 deletions(-) diff --git a/algorithms/backtrack/subsets.py b/algorithms/backtrack/subsets.py index a11c3c931..1c443024f 100644 --- a/algorithms/backtrack/subsets.py +++ b/algorithms/backtrack/subsets.py @@ -57,8 +57,3 @@ def subsets_v2(self, nums): for num in sorted(nums): res += [item+[num] for item in res] return res - - -test = [1, 2, 3] -print(test) -print(subsets(test)) diff --git a/algorithms/backtrack/subsets_unique.py b/algorithms/backtrack/subsets_unique.py index a99f25c35..da73a25ca 100644 --- a/algorithms/backtrack/subsets_unique.py +++ b/algorithms/backtrack/subsets_unique.py @@ -35,8 +35,3 @@ def backtrack(res, nums, stack, pos): res = set() backtrack(res, nums, [], 0) return list(res) - - -test = [1, 2, 2] -print(test) -print(subsets_unique(test)) diff --git a/algorithms/bfs/shortest_distance_from_all_buildings.py b/algorithms/bfs/shortest_distance_from_all_buildings.py index 48c41d063..4d4249cd2 100644 --- a/algorithms/bfs/shortest_distance_from_all_buildings.py +++ b/algorithms/bfs/shortest_distance_from_all_buildings.py @@ -38,6 +38,3 @@ def bfs(grid, matrix, i, j, count): matrix[k][l][0] += step+1 matrix[k][l][1] = count+1 q.append((k, l, step+1)) - -grid = [[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]] -print(shortest_distance(grid)) From b47e9d627160e42cb7a34920da4cf50f7c517a96 Mon Sep 17 00:00:00 2001 From: danghai Date: Thu, 19 Jul 2018 00:37:03 -0700 Subject: [PATCH 093/302] Update logo for all README --- README_CN.md | 4 ++-- README_GE.md | 2 +- README_JP.md | 4 ++-- README_KR.md | 4 ++-- README_PTBR.md | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README_CN.md b/README_CN.md index f3dc87fe9..c3a97c1ac 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) @@ -79,7 +79,7 @@ pip3 uninstall -y algorithms - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus.py) - [max_ones_index](algorithms/arrays/max_ones_index.py) - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) + - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) - [plus_one:加一运算](algorithms/arrays/plus_one.py) diff --git a/README_GE.md b/README_GE.md index 226deee2c..4f88a821b 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) diff --git a/README_JP.md b/README_JP.md index 7e3062e1d..8a89bbfdc 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) @@ -13,7 +13,7 @@ Pythonのデータ構造とアルゴリズム Python 3で開発された簡単で明確なデータ構造とアルゴリズムの例を紹介します。 ## 貢献 -貢献に興味を持っていただきありがとうございます。 このプロジェクトに貢献する方法はたくさんあります。 +貢献に興味を持っていただきありがとうございます。 このプロジェクトに貢献する方法はたくさんあります。 [簡単にコミュニティへ貢献するには](CONTRIBUTING_JP.md) diff --git a/README_KR.md b/README_KR.md index 91bfc0a38..c2f365e13 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) @@ -328,7 +328,7 @@ if __name__ == "__main__": - [tree](algorithms/tree/tree.py) - [union-find : 합집합 찾기](algorithms/union-find) - [count_islands](algorithms/union-find/count_islands.py) - + ## 기여자들 이 저장소는 아래 사람들에 의해 유지되고 있습니다. diff --git a/README_PTBR.md b/README_PTBR.md index 2a9e05fba..6f6b93a92 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português From dd52a82e733fe209758c0b44a077ba421c77da91 Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 16:22:51 +0200 Subject: [PATCH 094/302] added nearest neighbor algorithm --- .../machine-learning/nearest_neighbor.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 algorithms/machine-learning/nearest_neighbor.py diff --git a/algorithms/machine-learning/nearest_neighbor.py b/algorithms/machine-learning/nearest_neighbor.py new file mode 100644 index 000000000..64d102fdd --- /dev/null +++ b/algorithms/machine-learning/nearest_neighbor.py @@ -0,0 +1,57 @@ +import numpy + +# train set for the AND-function +trainSetAND = {(0,0) : 0, (0,1) :0, (1,0) : 0, (1,1) : 1} + +# train set for light or dark colors +trainSetLight = {(11, 98, 237) : 'L', (3, 39, 96) : 'D', (242, 226, 12) : 'L', (99, 93, 4) : 'D', +(232, 62, 32) : 'L', (119, 28, 11) : 'D', (25, 214, 47) : 'L', (89, 136, 247) : 'L', +(21, 34, 63) : 'D', (237, 99, 120) : 'L', (73, 33, 39) : 'D'} + +def distance(x,y): + """[summary] + HELPER-FUNCTION + calculates the (eulidean) distance between vector x and y. + + We use the numpy libriary + + Arguments: + x {[tuple]} -- [vector] + y {[tuple]} -- [vector] + """ + assert len(x) == len(y), "The vector must have same length" + import math + result = () + for i in range(len(x)): + result += (x[i] -y[i],) + return numpy.linalg.norm(result) + +def nearest_neighbor(x, tSet): + """[summary] + Implements the nearest neighbor algorithm + + Arguments: + x {[tupel]} -- [vector] + tSet {[dict]} -- [training set] + + Returns: + [type] -- [result of the AND-function] + """ + assert isinstance(x, tuple) and isinstance(tSet, dict) + currentKey = () + MAX = 32768 # max value + minD = MAX + for key in tSet: + d = distance(x, key) + if d < minD: + minD = d + currentKey = key + return tSet[currentKey] + +# Some test cases + +# print(nearest_neighbor((1,1), trainSetAND)) # => 1 +# print(nearest_neighbor((0,1), trainSetAND)) # => 0 +# print(nearest_neighbor((31, 242, 164), trainSetLight)) # => L +# print(nearest_neighbor((13, 94, 64), trainSetLight)) # => D +# print(nearest_neighbor((230, 52, 239), trainSetLight)) # => L \ No newline at end of file From 343600f4114e848d588d5d9859bdf3fd443435b5 Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 16:27:25 +0200 Subject: [PATCH 095/302] changed the readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4cf79cb1d..7ef7f522d 100644 --- a/README.md +++ b/README.md @@ -350,6 +350,8 @@ If you want to uninstall algorithms, it is as simple as: - [simplify_path](algorithms/unix/path/simplify_path.py) - [union-find](algorithms/union-find) - [count_islands](algorithms/union-find/count_islands.py) +- [machine-learning](algorithms/machine-learning) + - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) ## Contributors The repo is maintained by From d38649eaa006b30fa4faee6a7571068fded559e7 Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 16:37:28 +0200 Subject: [PATCH 096/302] changed variable names --- algorithms/machine-learning/nearest_neighbor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/algorithms/machine-learning/nearest_neighbor.py b/algorithms/machine-learning/nearest_neighbor.py index 64d102fdd..acd2f1c6e 100644 --- a/algorithms/machine-learning/nearest_neighbor.py +++ b/algorithms/machine-learning/nearest_neighbor.py @@ -38,15 +38,15 @@ def nearest_neighbor(x, tSet): [type] -- [result of the AND-function] """ assert isinstance(x, tuple) and isinstance(tSet, dict) - currentKey = () + current_key = () MAX = 32768 # max value - minD = MAX + min_d = MAX for key in tSet: d = distance(x, key) - if d < minD: - minD = d - currentKey = key - return tSet[currentKey] + if d < min_d: + min_d = d + current_key = key + return tSet[current_key] # Some test cases From b9bf25f5b6675b1fff04e7131b5b4e5c58e6ef90 Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 23:06:36 +0200 Subject: [PATCH 097/302] renamed the directory --- algorithms/{machine-learning => ml}/nearest_neighbor.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename algorithms/{machine-learning => ml}/nearest_neighbor.py (100%) diff --git a/algorithms/machine-learning/nearest_neighbor.py b/algorithms/ml/nearest_neighbor.py similarity index 100% rename from algorithms/machine-learning/nearest_neighbor.py rename to algorithms/ml/nearest_neighbor.py From 19c2596e1bf4a0be46256fefa653452235529d92 Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 23:17:33 +0200 Subject: [PATCH 098/302] added a test. removed test cases. renamed directory --- algorithms/ml/nearest_neighbor.py | 18 +----------------- tests/test_ml.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 tests/test_ml.py diff --git a/algorithms/ml/nearest_neighbor.py b/algorithms/ml/nearest_neighbor.py index acd2f1c6e..4dfc2718b 100644 --- a/algorithms/ml/nearest_neighbor.py +++ b/algorithms/ml/nearest_neighbor.py @@ -1,13 +1,5 @@ import numpy -# train set for the AND-function -trainSetAND = {(0,0) : 0, (0,1) :0, (1,0) : 0, (1,1) : 1} - -# train set for light or dark colors -trainSetLight = {(11, 98, 237) : 'L', (3, 39, 96) : 'D', (242, 226, 12) : 'L', (99, 93, 4) : 'D', -(232, 62, 32) : 'L', (119, 28, 11) : 'D', (25, 214, 47) : 'L', (89, 136, 247) : 'L', -(21, 34, 63) : 'D', (237, 99, 120) : 'L', (73, 33, 39) : 'D'} - def distance(x,y): """[summary] HELPER-FUNCTION @@ -46,12 +38,4 @@ def nearest_neighbor(x, tSet): if d < min_d: min_d = d current_key = key - return tSet[current_key] - -# Some test cases - -# print(nearest_neighbor((1,1), trainSetAND)) # => 1 -# print(nearest_neighbor((0,1), trainSetAND)) # => 0 -# print(nearest_neighbor((31, 242, 164), trainSetLight)) # => L -# print(nearest_neighbor((13, 94, 64), trainSetLight)) # => D -# print(nearest_neighbor((230, 52, 239), trainSetLight)) # => L \ No newline at end of file + return tSet[current_key] \ No newline at end of file diff --git a/tests/test_ml.py b/tests/test_ml.py new file mode 100644 index 000000000..495829ac6 --- /dev/null +++ b/tests/test_ml.py @@ -0,0 +1,28 @@ +from algorithms.ml.nearest_neighbor import ( + distance, + nearest_neighbor +) + +import unittest + +class TestML(unittest.TestCase): + def setUp(self): + # train set for the AND-function + self.trainSetAND = {(0,0) : 0, (0,1) :0, (1,0) : 0, (1,1) : 1} + + # train set for light or dark colors + self.trainSetLight = {(11, 98, 237) : 'L', (3, 39, 96) : 'D', (242, 226, 12) : 'L', (99, 93, 4) : 'D', + (232, 62, 32) : 'L', (119, 28, 11) : 'D', (25, 214, 47) : 'L', (89, 136, 247) : 'L', + (21, 34, 63) : 'D', (237, 99, 120) : 'L', (73, 33, 39) : 'D'} + def test_nearest_neighbor(self): + # AND-function + self.assertEqual(nearest_neighbor((1,1), self.trainSetAND), 1) + self.assertEqual(nearest_neighbor((0,1), self.trainSetAND), 0) + + # dark/light color test + self.assertEqual(nearest_neighbor((31, 242, 164), self.trainSetLight), 'L') + self.assertEqual(nearest_neighbor((13, 94, 64), self.trainSetLight), 'D') + self.assertEqual(nearest_neighbor((230, 52, 239), self.trainSetLight), 'L') + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 4abf64c592f00ce2c13bd11ecad1696dc9ea8e6c Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 23:25:23 +0200 Subject: [PATCH 099/302] added test for distance(...) --- tests/test_ml.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_ml.py b/tests/test_ml.py index 495829ac6..1d24cce7c 100644 --- a/tests/test_ml.py +++ b/tests/test_ml.py @@ -23,6 +23,7 @@ def test_nearest_neighbor(self): self.assertEqual(nearest_neighbor((31, 242, 164), self.trainSetLight), 'L') self.assertEqual(nearest_neighbor((13, 94, 64), self.trainSetLight), 'D') self.assertEqual(nearest_neighbor((230, 52, 239), self.trainSetLight), 'L') - + def test_distance(self): + self.assertAlmostEqual(distance((1,2,3), (1,0,-1)), 4.47, 2) if __name__ == "__main__": unittest.main() \ No newline at end of file From a9787738f1b6808d7eb979a9f42d24d0e540802b Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Tue, 24 Jul 2018 23:26:42 +0200 Subject: [PATCH 100/302] added empty lines --- tests/test_ml.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_ml.py b/tests/test_ml.py index 1d24cce7c..61852ec31 100644 --- a/tests/test_ml.py +++ b/tests/test_ml.py @@ -25,5 +25,7 @@ def test_nearest_neighbor(self): self.assertEqual(nearest_neighbor((230, 52, 239), self.trainSetLight), 'L') def test_distance(self): self.assertAlmostEqual(distance((1,2,3), (1,0,-1)), 4.47, 2) + + if __name__ == "__main__": unittest.main() \ No newline at end of file From 065898e79cce23ec4b0bf2587428d68c69ac92da Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Wed, 25 Jul 2018 16:16:58 +0200 Subject: [PATCH 101/302] removed math. added numpy.inf --- algorithms/ml/nearest_neighbor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/algorithms/ml/nearest_neighbor.py b/algorithms/ml/nearest_neighbor.py index 4dfc2718b..2ee801ded 100644 --- a/algorithms/ml/nearest_neighbor.py +++ b/algorithms/ml/nearest_neighbor.py @@ -12,7 +12,6 @@ def distance(x,y): y {[tuple]} -- [vector] """ assert len(x) == len(y), "The vector must have same length" - import math result = () for i in range(len(x)): result += (x[i] -y[i],) @@ -31,8 +30,7 @@ def nearest_neighbor(x, tSet): """ assert isinstance(x, tuple) and isinstance(tSet, dict) current_key = () - MAX = 32768 # max value - min_d = MAX + min_d = numpy.inf for key in tSet: d = distance(x, key) if d < min_d: From 913329fb1512de3b140620449d0580592c9f0482 Mon Sep 17 00:00:00 2001 From: Keon Date: Thu, 26 Jul 2018 22:09:51 -0700 Subject: [PATCH 102/302] update logo path (#382) --- README.md | 2 +- README_CN.md | 2 +- README_GE.md | 2 +- README_JP.md | 2 +- README_KR.md | 2 +- README_PTBR.md | 2 +- .../source/_static/logo}/128pxblack.png | Bin .../source/_static/logo}/128pxblack.svg | 0 .../source/_static/logo}/128pxblue.png | Bin .../source/_static/logo}/128pxblue.svg | 0 .../source/_static/logo}/128pxorange.png | Bin .../source/_static/logo}/128pxorange.svg | 0 .../source/_static/logo}/256pxblack.png | Bin .../source/_static/logo}/256pxblack.svg | 0 .../source/_static/logo}/256pxblue.png | Bin .../source/_static/logo}/256pxblue.svg | 0 .../source/_static/logo}/256pxorange.png | Bin .../source/_static/logo}/256pxorange.svg | 0 .../source/_static/logo}/512pxblack.png | Bin .../source/_static/logo}/512pxblack.svg | 0 .../source/_static/logo}/512pxblue.png | Bin .../source/_static/logo}/512pxblue.svg | 0 .../source/_static/logo}/512pxorange.png | Bin .../source/_static/logo}/512pxorange.svg | 0 {LogoDesins => docs/source/_static/logo}/add | 0 .../source/_static/logo}/logotype1black.png | Bin .../source/_static/logo}/logotype1black.svg | 0 .../source/_static/logo}/logotype1blue.png | Bin .../source/_static/logo}/logotype1blue.svg | 0 .../source/_static/logo}/logotype1orange.png | Bin .../source/_static/logo}/logotype1orange.svg | 0 .../source/_static/logo}/logotype2black.png | Bin .../source/_static/logo}/logotype2black.svg | 0 .../source/_static/logo}/logotype2blue.png | Bin .../source/_static/logo}/logotype2blue.svg | 0 .../source/_static/logo}/logotype2orange.png | Bin .../source/_static/logo}/logotype2orange.svg | 0 37 files changed, 6 insertions(+), 6 deletions(-) rename {LogoDesins => docs/source/_static/logo}/128pxblack.png (100%) rename {LogoDesins => docs/source/_static/logo}/128pxblack.svg (100%) rename {LogoDesins => docs/source/_static/logo}/128pxblue.png (100%) rename {LogoDesins => docs/source/_static/logo}/128pxblue.svg (100%) rename {LogoDesins => docs/source/_static/logo}/128pxorange.png (100%) rename {LogoDesins => docs/source/_static/logo}/128pxorange.svg (100%) rename {LogoDesins => docs/source/_static/logo}/256pxblack.png (100%) rename {LogoDesins => docs/source/_static/logo}/256pxblack.svg (100%) rename {LogoDesins => docs/source/_static/logo}/256pxblue.png (100%) rename {LogoDesins => docs/source/_static/logo}/256pxblue.svg (100%) rename {LogoDesins => docs/source/_static/logo}/256pxorange.png (100%) rename {LogoDesins => docs/source/_static/logo}/256pxorange.svg (100%) rename {LogoDesins => docs/source/_static/logo}/512pxblack.png (100%) rename {LogoDesins => docs/source/_static/logo}/512pxblack.svg (100%) rename {LogoDesins => docs/source/_static/logo}/512pxblue.png (100%) rename {LogoDesins => docs/source/_static/logo}/512pxblue.svg (100%) rename {LogoDesins => docs/source/_static/logo}/512pxorange.png (100%) rename {LogoDesins => docs/source/_static/logo}/512pxorange.svg (100%) rename {LogoDesins => docs/source/_static/logo}/add (100%) rename {LogoDesins => docs/source/_static/logo}/logotype1black.png (100%) rename {LogoDesins => docs/source/_static/logo}/logotype1black.svg (100%) rename {LogoDesins => docs/source/_static/logo}/logotype1blue.png (100%) rename {LogoDesins => docs/source/_static/logo}/logotype1blue.svg (100%) rename {LogoDesins => docs/source/_static/logo}/logotype1orange.png (100%) rename {LogoDesins => docs/source/_static/logo}/logotype1orange.svg (100%) rename {LogoDesins => docs/source/_static/logo}/logotype2black.png (100%) rename {LogoDesins => docs/source/_static/logo}/logotype2black.svg (100%) rename {LogoDesins => docs/source/_static/logo}/logotype2blue.png (100%) rename {LogoDesins => docs/source/_static/logo}/logotype2blue.svg (100%) rename {LogoDesins => docs/source/_static/logo}/logotype2orange.png (100%) rename {LogoDesins => docs/source/_static/logo}/logotype2orange.svg (100%) diff --git a/README.md b/README.md index 4cf79cb1d..c736a423f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) diff --git a/README_CN.md b/README_CN.md index c3a97c1ac..bd45839e0 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) diff --git a/README_GE.md b/README_GE.md index 4f88a821b..be908bc28 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) diff --git a/README_JP.md b/README_JP.md index 8a89bbfdc..c0a56c2bf 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) diff --git a/README_KR.md b/README_KR.md index c2f365e13..efd98483e 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) diff --git a/README_PTBR.md b/README_PTBR.md index 6f6b93a92..2870a1546 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -1,4 +1,4 @@ -

+

[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português diff --git a/LogoDesins/128pxblack.png b/docs/source/_static/logo/128pxblack.png similarity index 100% rename from LogoDesins/128pxblack.png rename to docs/source/_static/logo/128pxblack.png diff --git a/LogoDesins/128pxblack.svg b/docs/source/_static/logo/128pxblack.svg similarity index 100% rename from LogoDesins/128pxblack.svg rename to docs/source/_static/logo/128pxblack.svg diff --git a/LogoDesins/128pxblue.png b/docs/source/_static/logo/128pxblue.png similarity index 100% rename from LogoDesins/128pxblue.png rename to docs/source/_static/logo/128pxblue.png diff --git a/LogoDesins/128pxblue.svg b/docs/source/_static/logo/128pxblue.svg similarity index 100% rename from LogoDesins/128pxblue.svg rename to docs/source/_static/logo/128pxblue.svg diff --git a/LogoDesins/128pxorange.png b/docs/source/_static/logo/128pxorange.png similarity index 100% rename from LogoDesins/128pxorange.png rename to docs/source/_static/logo/128pxorange.png diff --git a/LogoDesins/128pxorange.svg b/docs/source/_static/logo/128pxorange.svg similarity index 100% rename from LogoDesins/128pxorange.svg rename to docs/source/_static/logo/128pxorange.svg diff --git a/LogoDesins/256pxblack.png b/docs/source/_static/logo/256pxblack.png similarity index 100% rename from LogoDesins/256pxblack.png rename to docs/source/_static/logo/256pxblack.png diff --git a/LogoDesins/256pxblack.svg b/docs/source/_static/logo/256pxblack.svg similarity index 100% rename from LogoDesins/256pxblack.svg rename to docs/source/_static/logo/256pxblack.svg diff --git a/LogoDesins/256pxblue.png b/docs/source/_static/logo/256pxblue.png similarity index 100% rename from LogoDesins/256pxblue.png rename to docs/source/_static/logo/256pxblue.png diff --git a/LogoDesins/256pxblue.svg b/docs/source/_static/logo/256pxblue.svg similarity index 100% rename from LogoDesins/256pxblue.svg rename to docs/source/_static/logo/256pxblue.svg diff --git a/LogoDesins/256pxorange.png b/docs/source/_static/logo/256pxorange.png similarity index 100% rename from LogoDesins/256pxorange.png rename to docs/source/_static/logo/256pxorange.png diff --git a/LogoDesins/256pxorange.svg b/docs/source/_static/logo/256pxorange.svg similarity index 100% rename from LogoDesins/256pxorange.svg rename to docs/source/_static/logo/256pxorange.svg diff --git a/LogoDesins/512pxblack.png b/docs/source/_static/logo/512pxblack.png similarity index 100% rename from LogoDesins/512pxblack.png rename to docs/source/_static/logo/512pxblack.png diff --git a/LogoDesins/512pxblack.svg b/docs/source/_static/logo/512pxblack.svg similarity index 100% rename from LogoDesins/512pxblack.svg rename to docs/source/_static/logo/512pxblack.svg diff --git a/LogoDesins/512pxblue.png b/docs/source/_static/logo/512pxblue.png similarity index 100% rename from LogoDesins/512pxblue.png rename to docs/source/_static/logo/512pxblue.png diff --git a/LogoDesins/512pxblue.svg b/docs/source/_static/logo/512pxblue.svg similarity index 100% rename from LogoDesins/512pxblue.svg rename to docs/source/_static/logo/512pxblue.svg diff --git a/LogoDesins/512pxorange.png b/docs/source/_static/logo/512pxorange.png similarity index 100% rename from LogoDesins/512pxorange.png rename to docs/source/_static/logo/512pxorange.png diff --git a/LogoDesins/512pxorange.svg b/docs/source/_static/logo/512pxorange.svg similarity index 100% rename from LogoDesins/512pxorange.svg rename to docs/source/_static/logo/512pxorange.svg diff --git a/LogoDesins/add b/docs/source/_static/logo/add similarity index 100% rename from LogoDesins/add rename to docs/source/_static/logo/add diff --git a/LogoDesins/logotype1black.png b/docs/source/_static/logo/logotype1black.png similarity index 100% rename from LogoDesins/logotype1black.png rename to docs/source/_static/logo/logotype1black.png diff --git a/LogoDesins/logotype1black.svg b/docs/source/_static/logo/logotype1black.svg similarity index 100% rename from LogoDesins/logotype1black.svg rename to docs/source/_static/logo/logotype1black.svg diff --git a/LogoDesins/logotype1blue.png b/docs/source/_static/logo/logotype1blue.png similarity index 100% rename from LogoDesins/logotype1blue.png rename to docs/source/_static/logo/logotype1blue.png diff --git a/LogoDesins/logotype1blue.svg b/docs/source/_static/logo/logotype1blue.svg similarity index 100% rename from LogoDesins/logotype1blue.svg rename to docs/source/_static/logo/logotype1blue.svg diff --git a/LogoDesins/logotype1orange.png b/docs/source/_static/logo/logotype1orange.png similarity index 100% rename from LogoDesins/logotype1orange.png rename to docs/source/_static/logo/logotype1orange.png diff --git a/LogoDesins/logotype1orange.svg b/docs/source/_static/logo/logotype1orange.svg similarity index 100% rename from LogoDesins/logotype1orange.svg rename to docs/source/_static/logo/logotype1orange.svg diff --git a/LogoDesins/logotype2black.png b/docs/source/_static/logo/logotype2black.png similarity index 100% rename from LogoDesins/logotype2black.png rename to docs/source/_static/logo/logotype2black.png diff --git a/LogoDesins/logotype2black.svg b/docs/source/_static/logo/logotype2black.svg similarity index 100% rename from LogoDesins/logotype2black.svg rename to docs/source/_static/logo/logotype2black.svg diff --git a/LogoDesins/logotype2blue.png b/docs/source/_static/logo/logotype2blue.png similarity index 100% rename from LogoDesins/logotype2blue.png rename to docs/source/_static/logo/logotype2blue.png diff --git a/LogoDesins/logotype2blue.svg b/docs/source/_static/logo/logotype2blue.svg similarity index 100% rename from LogoDesins/logotype2blue.svg rename to docs/source/_static/logo/logotype2blue.svg diff --git a/LogoDesins/logotype2orange.png b/docs/source/_static/logo/logotype2orange.png similarity index 100% rename from LogoDesins/logotype2orange.png rename to docs/source/_static/logo/logotype2orange.png diff --git a/LogoDesins/logotype2orange.svg b/docs/source/_static/logo/logotype2orange.svg similarity index 100% rename from LogoDesins/logotype2orange.svg rename to docs/source/_static/logo/logotype2orange.svg From 5fd9d6dad35cf00c6c1a2191bc5977a9e5a761c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Sun, 29 Jul 2018 01:04:30 +0800 Subject: [PATCH 103/302] fix typo (#385) fix typo --- README_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_CN.md b/README_CN.md index bd45839e0..4dc5cfcc7 100644 --- a/README_CN.md +++ b/README_CN.md @@ -37,7 +37,7 @@ python3 -m unittest tests.test_sort 如下代码运行所有测试代码: ``` -pyhton3 -m pytest tests +python3 -m pytest tests ``` From b7d5db16a1534fe116e85dcc8451ee669158539a Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Sun, 29 Jul 2018 06:51:52 -0700 Subject: [PATCH 104/302] Add test for map (#386) --- algorithms/map/__init__.py | 2 + algorithms/map/hashtable.py | 93 ----------- algorithms/map/separate_chaining_hashtable.py | 59 ------- tests/test_map.py | 152 ++++++++++++++++++ 4 files changed, 154 insertions(+), 152 deletions(-) create mode 100644 algorithms/map/__init__.py create mode 100644 tests/test_map.py diff --git a/algorithms/map/__init__.py b/algorithms/map/__init__.py new file mode 100644 index 000000000..a663c8a30 --- /dev/null +++ b/algorithms/map/__init__.py @@ -0,0 +1,2 @@ +from .hashtable import * +from .separate_chaining_hashtable import * diff --git a/algorithms/map/hashtable.py b/algorithms/map/hashtable.py index 1c98ee22c..f579c0b0d 100644 --- a/algorithms/map/hashtable.py +++ b/algorithms/map/hashtable.py @@ -1,6 +1,3 @@ -from unittest import TestCase -import unittest - class HashTable(object): """ HashMap Data Type @@ -120,93 +117,3 @@ def __resize(self): for key, value in zip(keys, values): if key is not self._empty and key is not self._deleted: self.put(key, value) - - -class TestHashTable(TestCase): - def test_one_entry(self): - m = HashTable(10) - m.put(1, '1') - self.assertEqual('1', m.get(1)) - - def test_add_entry_bigger_than_table_size(self): - m = HashTable(10) - m.put(11, '1') - self.assertEqual('1', m.get(11)) - - def test_get_none_if_key_missing_and_hash_collision(self): - m = HashTable(10) - m.put(1, '1') - self.assertEqual(None, m.get(11)) - - def test_two_entries_with_same_hash(self): - m = HashTable(10) - m.put(1, '1') - m.put(11, '11') - self.assertEqual('1', m.get(1)) - self.assertEqual('11', m.get(11)) - - def test_get_on_full_table_does_halts(self): - # and does not search forever - m = HashTable(10) - for i in range(10, 20): - m.put(i, i) - self.assertEqual(None, m.get(1)) - - def test_delete_key(self): - m = HashTable(10) - for i in range(5): - m.put(i, i**2) - m.del_(1) - self.assertEqual(None, m.get(1)) - self.assertEqual(4,m.get(2)) - - def test_delete_key_and_reassign(self): - m = HashTable(10) - m.put(1, 1) - del m[1] - m.put(1, 2) - self.assertEqual(2, m.get(1)) - - def test_assigning_to_full_table_throws_error(self): - m = HashTable(3) - m.put(1, 1) - m.put(2, 2) - m.put(3, 3) - with self.assertRaises(ValueError): - m.put(4, 4) - - def test_len_trivial(self): - m = HashTable(10) - self.assertEqual(0, len(m)) - for i in range(10): - m.put(i, i) - self.assertEqual(i + 1, len(m)) - - def test_len_after_deletions(self): - m = HashTable(10) - m.put(1, 1) - self.assertEqual(1, len(m)) - m.del_(1) - self.assertEqual(0, len(m)) - m.put(11, 42) - self.assertEqual(1, len(m)) - - def test_resizable_hash_table(self): - m = ResizableHashTable() - self.assertEqual(ResizableHashTable.MIN_SIZE, m.size) - for i in range(ResizableHashTable.MIN_SIZE): - m.put(i, 'foo') - self.assertEqual(ResizableHashTable.MIN_SIZE * 2, m.size) - self.assertEqual('foo', m.get(1)) - self.assertEqual('foo', m.get(3)) - self.assertEqual('foo', m.get(ResizableHashTable.MIN_SIZE - 1)) - - def test_fill_up_the_limit(self): - m = HashTable(10) - for i in range(10): - m.put(i,i**2) - for i in range(10): - self.assertEqual(i**2,m.get(i)) - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/algorithms/map/separate_chaining_hashtable.py b/algorithms/map/separate_chaining_hashtable.py index 5feb50af8..fecb251fa 100644 --- a/algorithms/map/separate_chaining_hashtable.py +++ b/algorithms/map/separate_chaining_hashtable.py @@ -82,62 +82,3 @@ def __delitem__(self, key): def __setitem__(self, key, value): self.put(key, value) - - -class TestSeparateChainingHashTable(unittest.TestCase): - def test_one_entry(self): - m = SeparateChainingHashTable(10) - m.put(1, '1') - self.assertEqual('1', m.get(1)) - - def test_two_entries_with_same_hash(self): - m = SeparateChainingHashTable(10) - m.put(1, '1') - m.put(11, '11') - self.assertEqual('1', m.get(1)) - self.assertEqual('11', m.get(11)) - - def test_len_trivial(self): - m = SeparateChainingHashTable(10) - self.assertEqual(0, len(m)) - for i in range(10): - m.put(i, i) - self.assertEqual(i + 1, len(m)) - - def test_len_after_deletions(self): - m = SeparateChainingHashTable(10) - m.put(1, 1) - self.assertEqual(1, len(m)) - m.del_(1) - self.assertEqual(0, len(m)) - m.put(11, 42) - self.assertEqual(1, len(m)) - - def test_delete_key(self): - m = SeparateChainingHashTable(10) - for i in range(5): - m.put(i, i**2) - m.del_(1) - self.assertEqual(None, m.get(1)) - self.assertEqual(4, m.get(2)) - - def test_delete_key_and_reassign(self): - m = SeparateChainingHashTable(10) - m.put(1, 1) - del m[1] - m.put(1, 2) - self.assertEqual(2, m.get(1)) - - def test_add_entry_bigger_than_table_size(self): - m = SeparateChainingHashTable(10) - m.put(11, '1') - self.assertEqual('1', m.get(11)) - - def test_get_none_if_key_missing_and_hash_collision(self): - m = SeparateChainingHashTable(10) - m.put(1, '1') - self.assertEqual(None, m.get(11)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_map.py b/tests/test_map.py new file mode 100644 index 000000000..5786803e9 --- /dev/null +++ b/tests/test_map.py @@ -0,0 +1,152 @@ +from algorithms.map import ( + HashTable, ResizableHashTable, + Node, SeparateChainingHashTable +) + +import unittest + +class TestHashTable(unittest.TestCase): + def test_one_entry(self): + m = HashTable(10) + m.put(1, '1') + self.assertEqual('1', m.get(1)) + + def test_add_entry_bigger_than_table_size(self): + m = HashTable(10) + m.put(11, '1') + self.assertEqual('1', m.get(11)) + + def test_get_none_if_key_missing_and_hash_collision(self): + m = HashTable(10) + m.put(1, '1') + self.assertEqual(None, m.get(11)) + + def test_two_entries_with_same_hash(self): + m = HashTable(10) + m.put(1, '1') + m.put(11, '11') + self.assertEqual('1', m.get(1)) + self.assertEqual('11', m.get(11)) + + def test_get_on_full_table_does_halts(self): + # and does not search forever + m = HashTable(10) + for i in range(10, 20): + m.put(i, i) + self.assertEqual(None, m.get(1)) + + def test_delete_key(self): + m = HashTable(10) + for i in range(5): + m.put(i, i**2) + m.del_(1) + self.assertEqual(None, m.get(1)) + self.assertEqual(4,m.get(2)) + + def test_delete_key_and_reassign(self): + m = HashTable(10) + m.put(1, 1) + del m[1] + m.put(1, 2) + self.assertEqual(2, m.get(1)) + + def test_assigning_to_full_table_throws_error(self): + m = HashTable(3) + m.put(1, 1) + m.put(2, 2) + m.put(3, 3) + with self.assertRaises(ValueError): + m.put(4, 4) + + def test_len_trivial(self): + m = HashTable(10) + self.assertEqual(0, len(m)) + for i in range(10): + m.put(i, i) + self.assertEqual(i + 1, len(m)) + + def test_len_after_deletions(self): + m = HashTable(10) + m.put(1, 1) + self.assertEqual(1, len(m)) + m.del_(1) + self.assertEqual(0, len(m)) + m.put(11, 42) + self.assertEqual(1, len(m)) + + def test_resizable_hash_table(self): + m = ResizableHashTable() + self.assertEqual(ResizableHashTable.MIN_SIZE, m.size) + for i in range(ResizableHashTable.MIN_SIZE): + m.put(i, 'foo') + self.assertEqual(ResizableHashTable.MIN_SIZE * 2, m.size) + self.assertEqual('foo', m.get(1)) + self.assertEqual('foo', m.get(3)) + self.assertEqual('foo', m.get(ResizableHashTable.MIN_SIZE - 1)) + + def test_fill_up_the_limit(self): + m = HashTable(10) + for i in range(10): + m.put(i,i**2) + for i in range(10): + self.assertEqual(i**2,m.get(i)) + + +class TestSeparateChainingHashTable(unittest.TestCase): + def test_one_entry(self): + m = SeparateChainingHashTable(10) + m.put(1, '1') + self.assertEqual('1', m.get(1)) + + def test_two_entries_with_same_hash(self): + m = SeparateChainingHashTable(10) + m.put(1, '1') + m.put(11, '11') + self.assertEqual('1', m.get(1)) + self.assertEqual('11', m.get(11)) + + def test_len_trivial(self): + m = SeparateChainingHashTable(10) + self.assertEqual(0, len(m)) + for i in range(10): + m.put(i, i) + self.assertEqual(i + 1, len(m)) + + def test_len_after_deletions(self): + m = SeparateChainingHashTable(10) + m.put(1, 1) + self.assertEqual(1, len(m)) + m.del_(1) + self.assertEqual(0, len(m)) + m.put(11, 42) + self.assertEqual(1, len(m)) + + def test_delete_key(self): + m = SeparateChainingHashTable(10) + for i in range(5): + m.put(i, i**2) + m.del_(1) + self.assertEqual(None, m.get(1)) + self.assertEqual(4, m.get(2)) + + def test_delete_key_and_reassign(self): + m = SeparateChainingHashTable(10) + m.put(1, 1) + del m[1] + m.put(1, 2) + self.assertEqual(2, m.get(1)) + + def test_add_entry_bigger_than_table_size(self): + m = SeparateChainingHashTable(10) + m.put(11, '1') + self.assertEqual('1', m.get(11)) + + def test_get_none_if_key_missing_and_hash_collision(self): + m = SeparateChainingHashTable(10) + m.put(1, '1') + self.assertEqual(None, m.get(11)) + + + +if __name__ == "__main__": + unittest.main() From d5ded338b148de000341ae9acb946138ba84190d Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Sun, 29 Jul 2018 16:54:09 +0200 Subject: [PATCH 105/302] removed numpy --- algorithms/ml/nearest_neighbor.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/algorithms/ml/nearest_neighbor.py b/algorithms/ml/nearest_neighbor.py index 2ee801ded..0029c129d 100644 --- a/algorithms/ml/nearest_neighbor.py +++ b/algorithms/ml/nearest_neighbor.py @@ -1,11 +1,9 @@ -import numpy +import math def distance(x,y): """[summary] HELPER-FUNCTION calculates the (eulidean) distance between vector x and y. - - We use the numpy libriary Arguments: x {[tuple]} -- [vector] @@ -13,9 +11,13 @@ def distance(x,y): """ assert len(x) == len(y), "The vector must have same length" result = () + sum = 0 for i in range(len(x)): result += (x[i] -y[i],) - return numpy.linalg.norm(result) + for component in result: + sum += component**2 + return math.sqrt(sum) + def nearest_neighbor(x, tSet): """[summary] @@ -30,7 +32,7 @@ def nearest_neighbor(x, tSet): """ assert isinstance(x, tuple) and isinstance(tSet, dict) current_key = () - min_d = numpy.inf + min_d = math.inf for key in tSet: d = distance(x, key) if d < min_d: From 08404189801ac2e7c14c6ba2cc2a6454f03445cc Mon Sep 17 00:00:00 2001 From: danghai Date: Wed, 1 Aug 2018 20:51:19 -0700 Subject: [PATCH 106/302] Replace min.inf by float(inf) --- algorithms/ml/nearest_neighbor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/algorithms/ml/nearest_neighbor.py b/algorithms/ml/nearest_neighbor.py index 0029c129d..d0fabab15 100644 --- a/algorithms/ml/nearest_neighbor.py +++ b/algorithms/ml/nearest_neighbor.py @@ -17,25 +17,25 @@ def distance(x,y): for component in result: sum += component**2 return math.sqrt(sum) - + def nearest_neighbor(x, tSet): """[summary] - Implements the nearest neighbor algorithm + Implements the nearest neighbor algorithm Arguments: x {[tupel]} -- [vector] tSet {[dict]} -- [training set] - + Returns: [type] -- [result of the AND-function] """ assert isinstance(x, tuple) and isinstance(tSet, dict) current_key = () - min_d = math.inf + min_d = float('inf') for key in tSet: d = distance(x, key) if d < min_d: min_d = d current_key = key - return tSet[current_key] \ No newline at end of file + return tSet[current_key] From 48072b41ace2c18636f965dc3ec40c8f79cbba02 Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Thu, 2 Aug 2018 07:27:07 -0700 Subject: [PATCH 107/302] PR to add some problem (#378) * Add longest_common_prefix to string * Add brute force way for is_rotated, add rotate to string * Add first_unique_char to string * Add repeat_substring to string --- README.md | 4 ++ algorithms/strings/__init__.py | 4 ++ algorithms/strings/first_unique_char.py | 27 +++++++++ algorithms/strings/is_rotated.py | 18 +++++- algorithms/strings/longest_common_prefix.py | 66 +++++++++++++++++++++ algorithms/strings/repeat_substring.py | 25 ++++++++ algorithms/strings/rotate.py | 18 ++++++ tests/test_strings.py | 46 +++++++++++++- 8 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 algorithms/strings/first_unique_char.py create mode 100644 algorithms/strings/longest_common_prefix.py create mode 100644 algorithms/strings/repeat_substring.py create mode 100644 algorithms/strings/rotate.py diff --git a/README.md b/README.md index ea8a841f7..7bb26892d 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,10 @@ If you want to uninstall algorithms, it is as simple as: - [count_binary_substring](algorithms/strings/count_binary_substring.py) - [repeat_string](algorithms/strings/repeat_string.py) - [min_distance](algorithms/strings/min_distance.py) + - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) + - [rotate](algorithms/strings/rotate.py) + - [first_unique_char](algorithms/strings/first_unique_char.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index d7ae4b673..98306f61d 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -30,3 +30,7 @@ from .repeat_string import * from .text_justification import * from .min_distance import * +from .longest_common_prefix import * +from .rotate import * +from .first_unique_char import * +from .repeat_substring import * diff --git a/algorithms/strings/first_unique_char.py b/algorithms/strings/first_unique_char.py new file mode 100644 index 000000000..44ba05e49 --- /dev/null +++ b/algorithms/strings/first_unique_char.py @@ -0,0 +1,27 @@ +""" +Given a string, find the first non-repeating character in it and return it's +index. If it doesn't exist, return -1. + +For example: +s = "leetcode" +return 0. + +s = "loveleetcode", +return 2. + +Reference: https://leetcode.com/problems/first-unique-character-in-a-string/description/ +""" +def first_unique_char(s): + """ + :type s: str + :rtype: int + """ + if (len(s) == 1): + return 0 + ban = [] + for i in range(len(s)): + if all(s[i] != s[k] for k in range(i + 1, len(s))) == True and s[i] not in ban: + return i + else: + ban.append(s[i]) + return -1 diff --git a/algorithms/strings/is_rotated.py b/algorithms/strings/is_rotated.py index a68d62d04..a827fb497 100644 --- a/algorithms/strings/is_rotated.py +++ b/algorithms/strings/is_rotated.py @@ -6,10 +6,26 @@ accepts two strings returns bool +Reference: https://leetcode.com/problems/rotate-string/description/ """ def is_rotated(s1, s2): if len(s1) == len(s2): return s2 in s1 + s1 else: - return False \ No newline at end of file + return False + +""" +Another solution: brutal force +Complexity: O(N^2) +""" +def is_rotated_v1(s1, s2): + if len(s1) != len(s2): + return False + if len(s1) == 0: + return True + + for c in range(len(s1)): + if all(s1[(c + i) % len(s1)] == s2[i] for i in range(len(s1))): + return True + return False diff --git a/algorithms/strings/longest_common_prefix.py b/algorithms/strings/longest_common_prefix.py new file mode 100644 index 000000000..80facc934 --- /dev/null +++ b/algorithms/strings/longest_common_prefix.py @@ -0,0 +1,66 @@ +""" +Write a function to find the longest common prefix string amongst an array of strings. + +If there is no common prefix, return an empty string "". + +Example 1: +Input: ["flower","flow","flight"] +Output: "fl" + +Example 2: +Input: ["dog","racecar","car"] +Output: "" +Explanation: There is no common prefix among the input strings. + +Reference: https://leetcode.com/problems/longest-common-prefix/description/ +""" + +""" +First solution: Horizontal scanning +""" +def common_prefix(s1, s2): + "Return prefix common of 2 strings" + if not s1 or not s2: + return "" + k = 0 + while s1[k] == s2[k]: + k = k + 1 + if k >= len(s1) or k >= len(s2): + return s1[0:k] + return s1[0:k] + +def longest_common_prefix_v1(strs): + if not strs: + return "" + result = strs[0] + for i in range(len(strs)): + result = common_prefix(result, strs[i]) + return result + +""" +Second solution: Vertical scanning +""" +def longest_common_prefix_v2(strs): + if not strs: + return "" + for i in range(len(strs[0])): + for string in strs[1:]: + if i == len(string) or string[i] != strs[0][i]: + return strs[0][0:i] + return strs[0] + +""" +Third solution: Divide and Conquer +""" +def longest_common_prefix_v3(strs): + if not strs: + return "" + return longest_common(strs, 0, len(strs) -1) + +def longest_common(strs, left, right): + if left == right: + return strs[left] + mid = (left + right) // 2 + lcp_left = longest_common(strs, left, mid) + lcp_right = longest_common(strs, mid + 1, right) + return common_prefix(lcp_left, lcp_right) diff --git a/algorithms/strings/repeat_substring.py b/algorithms/strings/repeat_substring.py new file mode 100644 index 000000000..0f26c2819 --- /dev/null +++ b/algorithms/strings/repeat_substring.py @@ -0,0 +1,25 @@ +""" +Given a non-empty string check if it can be constructed by taking +a substring of it and appending multiple copies of the substring together. + +For example: +Input: "abab" +Output: True +Explanation: It's the substring "ab" twice. + +Input: "aba" +Output: False + +Input: "abcabcabcabc" +Output: True +Explanation: It's the substring "abc" four times. + +Reference: https://leetcode.com/problems/repeated-substring-pattern/description/ +""" +def repeat_substring(s): + """ + :type s: str + :rtype: bool + """ + str = (s + s)[1:-1] + return s in str diff --git a/algorithms/strings/rotate.py b/algorithms/strings/rotate.py new file mode 100644 index 000000000..7f713baf5 --- /dev/null +++ b/algorithms/strings/rotate.py @@ -0,0 +1,18 @@ +""" +Given a strings s and int k, return a string that rotates k times + +For example, +rotate("hello", 2) return "llohe" +rotate("hello", 5) return "hello" +rotate("hello", 6) return "elloh" +rotate("hello", 7) return "llohe" + +accepts two strings +returns bool +""" +def rotate(s, k): + double_s = s + s + if k <= len(s): + return double_s[k:k + len(s)] + else: + return double_s[k-len(s):k] diff --git a/tests/test_strings.py b/tests/test_strings.py index 0c77ac12a..4474b75b2 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -9,7 +9,7 @@ int_to_roman, is_palindrome, is_palindrome_reverse, is_palindrome_two_pointer, is_palindrome_stack, - is_rotated, + is_rotated, is_rotated_v1, license_number, make_sentence, is_merge_recursive, is_merge_iterative, @@ -32,7 +32,11 @@ count_binary_substring, repeat_string, text_justification, - min_distance + min_distance, + longest_common_prefix_v1, longest_common_prefix_v2, longest_common_prefix_v3, + rotate, + first_unique_char, + repeat_substring ) import unittest @@ -201,6 +205,21 @@ def test_is_rotated(self): self.assertFalse(is_rotated("hello", "lloh")) self.assertTrue(is_rotated("", "")) + def test_is_rotated_v1(self): + self.assertTrue(is_rotated_v1("hello", "hello")) + self.assertTrue(is_rotated_v1("hello", "llohe")) + self.assertFalse(is_rotated_v1("hello", "helol")) + self.assertFalse(is_rotated_v1("hello", "lloh")) + self.assertTrue(is_rotated_v1("", "")) + + +class TestRotated(unittest.TestCase): + def test_rotate(self): + self.assertEqual("llohe", rotate("hello", 2)) + self.assertEqual("hello", rotate("hello", 5)) + self.assertEqual("elloh", rotate("hello", 6)) + self.assertEqual("llohe", rotate("hello", 7)) + class TestLicenseNumber(unittest.TestCase): """[summary] @@ -475,6 +494,29 @@ def test_min_distance(self): self.assertEqual(2, min_distance("sea", "eat")) self.assertEqual(6, min_distance("abAlgocrithmf", "Algorithmmd")) +class TestLongestCommonPrefix(unittest.TestCase): + def test_longest_common_prefix(self): + # Test first solution + self.assertEqual("fl", longest_common_prefix_v1(["flower","flow","flight"])) + self.assertEqual("", longest_common_prefix_v1(["dog","racecar","car"])) + # Test second solution + self.assertEqual("fl", longest_common_prefix_v2(["flower","flow","flight"])) + self.assertEqual("", longest_common_prefix_v2(["dog","racecar","car"])) + # Test third solution + self.assertEqual("fl", longest_common_prefix_v3(["flower","flow","flight"])) + self.assertEqual("", longest_common_prefix_v3(["dog","racecar","car"])) + +class TestFirstUniqueChar(unittest.TestCase): + def test_first_unique_char(self): + self.assertEqual(0, first_unique_char("leetcode")) + self.assertEqual(2, first_unique_char("loveleetcode")) + +class TestRepeatSubstring(unittest.TestCase): + def test_repeat_substring(self): + self.assertTrue(repeat_substring("abab")) + self.assertFalse(repeat_substring("aba")) + self.assertTrue(repeat_substring("abcabcabcabc")) + if __name__ == "__main__": unittest.main() From 3879607757f2e2a3d4e48a342636d6d593a840a0 Mon Sep 17 00:00:00 2001 From: RenliangShi <41174348+RenliangShi@users.noreply.github.com> Date: Mon, 6 Aug 2018 11:03:03 +0800 Subject: [PATCH 108/302] generate_parenthesis (#384) * generate_parenthesis * format --- algorithms/backtrack/generate_parenthesis.py | 20 +++++++++++++++++--- tests/test_backtrack.py | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/algorithms/backtrack/generate_parenthesis.py b/algorithms/backtrack/generate_parenthesis.py index 9b9eb8cf1..073cec96a 100644 --- a/algorithms/backtrack/generate_parenthesis.py +++ b/algorithms/backtrack/generate_parenthesis.py @@ -14,16 +14,30 @@ """ -def generate_parenthesis(n): +def generate_parenthesis_v1(n): def add_pair(res, s, left, right): if left == 0 and right == 0: res.append(s) return if right > 0: - add_pair(res, s+")", left, right-1) + add_pair(res, s + ")", left, right - 1) if left > 0: - add_pair(res, s+"(", left-1, right+1) + add_pair(res, s + "(", left - 1, right + 1) res = [] add_pair(res, "", n, 0) return res + + +def generate_parenthesis_v2(n): + def add_pair(res, s, left, right): + if left == 0 and right == 0: + res.append(s) + if left > 0: + add_pair(res, s + "(", left - 1, right) + if right > 0 and left < right: + add_pair(res, s + ")", left, right - 1) + + res = [] + add_pair(res, "", n, n) + return res diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py index dd290f759..c53f9f1e1 100644 --- a/tests/test_backtrack.py +++ b/tests/test_backtrack.py @@ -11,6 +11,7 @@ ) import unittest +from algorithms.backtrack.generate_parenthesis import * class TestAddOperator(unittest.TestCase): @@ -170,3 +171,16 @@ def test_pattern_match(self): self.assertTrue(pattern_match(pattern1, string1)) self.assertTrue(pattern_match(pattern2, string2)) self.assertFalse(pattern_match(pattern3, string3)) + +class TestGenerateParenthesis(unittest.TestCase): + + def test_generate_parenthesis(self): + self.assertEqual(generate_parenthesis_v1(2), ['()()', '(())']) + self.assertEqual(generate_parenthesis_v1(3), ['()()()', '()(())', '(())()', '(()())', '((()))']) + self.assertEqual(generate_parenthesis_v2(2), ['(())', '()()']) + self.assertEqual(generate_parenthesis_v2(3), ['((()))', '(()())', '(())()', '()(())', '()()()']) + +if __name__ == '__main__': + + unittest.main() + From 508b9918eee7f10d6f2e494f3bfc713a014c7c9a Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Sat, 11 Aug 2018 17:36:31 -0700 Subject: [PATCH 109/302] Fix longest_non_repeat by sliding windown method (#390) Fixes #388 --- algorithms/arrays/longest_non_repeat.py | 22 ++++++++++------------ tests/test_array.py | 12 ++++++++++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/algorithms/arrays/longest_non_repeat.py b/algorithms/arrays/longest_non_repeat.py index e97efcca0..1d083fb0e 100644 --- a/algorithms/arrays/longest_non_repeat.py +++ b/algorithms/arrays/longest_non_repeat.py @@ -12,19 +12,17 @@ def longest_non_repeat_v1(string): """ - Finds the length of the longest substring - without repeating characters. + Apply slide windown. """ - if string is None: - return 0 - temp = [] - max_len = 0 - for i in string: - if i in temp: - temp = [] - temp.append(i) - max_len = max(max_len, len(temp)) - return max_len + dict = {} + max_length = 0 + j = 0 + for i in range(len(string)): + if string[i] in dict: + j = max(dict[string[i]], j) + dict[string[i]] = i + 1 + max_length = max(max_length, i - j + 1) + return max_length def longest_non_repeat_v2(string): diff --git a/tests/test_array.py b/tests/test_array.py index 47e24347a..3fd6e0882 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -147,6 +147,12 @@ def test_longest_non_repeat_v1(self): string = "pwwkew" self.assertEqual(longest_non_repeat_v1(string), 3) + string = "dvdf" + self.assertEqual(longest_non_repeat_v1(string), 3) + + string = "asjrgapa" + self.assertEqual(longest_non_repeat_v1(string), 6) + def test_longest_non_repeat_v2(self): string = "abcabcbb" @@ -158,6 +164,12 @@ def test_longest_non_repeat_v2(self): string = "pwwkew" self.assertEqual(longest_non_repeat_v2(string), 3) + string = "dvdf" + self.assertEqual(longest_non_repeat_v2(string), 3) + + string = "asjrgapa" + self.assertEqual(longest_non_repeat_v2(string), 6) + class TestMaxOnesIndex(unittest.TestCase): From b02e3bfe362a68b05f5880a084dcb86a9cf889da Mon Sep 17 00:00:00 2001 From: Hai Hoang Dang Date: Tue, 14 Aug 2018 04:52:25 -0700 Subject: [PATCH 110/302] PR to add some hash problems (#387) * Add word_pattern in hash map * Add ismorphic to hash table * Add is_anagram to hash table * Add find_keyboard_row to set * Fix the issue --- README.md | 4 +++ algorithms/map/__init__.py | 3 +++ algorithms/map/is_anagram.py | 29 +++++++++++++++++++++ algorithms/map/is_isomorphic.py | 40 +++++++++++++++++++++++++++++ algorithms/map/word_pattern.py | 40 +++++++++++++++++++++++++++++ algorithms/set/__init__.py | 1 + algorithms/set/find_keyboard_row.py | 26 +++++++++++++++++++ tests/test_map.py | 27 ++++++++++++++++++- tests/test_set.py | 10 ++++++++ 9 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 algorithms/map/is_anagram.py create mode 100644 algorithms/map/is_isomorphic.py create mode 100644 algorithms/map/word_pattern.py create mode 100644 algorithms/set/__init__.py create mode 100644 algorithms/set/find_keyboard_row.py create mode 100644 tests/test_set.py diff --git a/README.md b/README.md index 7bb26892d..934100148 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,9 @@ If you want to uninstall algorithms, it is as simple as: - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - [randomized_set](algorithms/map/randomized_set.py) - [valid_sudoku](algorithms/map/valid_sudoku.py) + - [word_pattern](algorithms/map/word_pattern.py) + - [is_isomorphic](algorithms/map/is_isomorphic.py) + - [is_anagram](algorithms/map/is_anagram.py) - [maths](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) @@ -231,6 +234,7 @@ If you want to uninstall algorithms, it is as simple as: - [set](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) + - [find_keyboard_row](algorithms/set/find_keyboard_row.py) - [sort](algorithms/sort) - [bitonic_sort](algorithms/sort/bitonic_sort.py) - [bogo_sort](algorithms/sort/bogo_sort.py) diff --git a/algorithms/map/__init__.py b/algorithms/map/__init__.py index a663c8a30..233348d37 100644 --- a/algorithms/map/__init__.py +++ b/algorithms/map/__init__.py @@ -1,2 +1,5 @@ from .hashtable import * from .separate_chaining_hashtable import * +from .word_pattern import * +from .is_isomorphic import * +from .is_anagram import * diff --git a/algorithms/map/is_anagram.py b/algorithms/map/is_anagram.py new file mode 100644 index 000000000..066d8c20f --- /dev/null +++ b/algorithms/map/is_anagram.py @@ -0,0 +1,29 @@ +""" +Given two strings s and t , write a function to determine if t is an anagram of s. + +Example 1: +Input: s = "anagram", t = "nagaram" +Output: true + +Example 2: +Input: s = "rat", t = "car" +Output: false + +Note: +You may assume the string contains only lowercase alphabets. + +Reference: https://leetcode.com/problems/valid-anagram/description/ +""" +def is_anagram(s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + maps = {} + mapt = {} + for i in s: + maps[i] = maps.get(i, 0) + 1 + for i in t: + mapt[i] = mapt.get(i, 0) + 1 + return maps == mapt diff --git a/algorithms/map/is_isomorphic.py b/algorithms/map/is_isomorphic.py new file mode 100644 index 000000000..62342e5e4 --- /dev/null +++ b/algorithms/map/is_isomorphic.py @@ -0,0 +1,40 @@ +""" +Given two strings s and t, determine if they are isomorphic. +Two strings are isomorphic if the characters in s can be replaced to get t. +All occurrences of a character must be replaced with another character while +preserving the order of characters. No two characters may map to the same +character but a character may map to itself. + +Example 1: +Input: s = "egg", t = "add" +Output: true + +Example 2: +Input: s = "foo", t = "bar" +Output: false + +Example 3: +Input: s = "paper", t = "title" +Output: true +Reference: https://leetcode.com/problems/isomorphic-strings/description/ +""" +def is_isomorphic(s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if len(s) != len(t): + return False + dict = {} + set_value = set() + for i in range(len(s)): + if s[i] not in dict: + if t[i] in set_value: + return False + dict[s[i]] = t[i] + set_value.add(t[i]) + else: + if dict[s[i]] != t[i]: + return False + return True diff --git a/algorithms/map/word_pattern.py b/algorithms/map/word_pattern.py new file mode 100644 index 000000000..bee2f7a91 --- /dev/null +++ b/algorithms/map/word_pattern.py @@ -0,0 +1,40 @@ +""" +Given a pattern and a string str, find if str follows the same pattern. +Here follow means a full match, such that there is a bijection between a +letter in pattern and a non-empty word in str. + +Example 1: +Input: pattern = "abba", str = "dog cat cat dog" +Output: true + +Example 2: +Input:pattern = "abba", str = "dog cat cat fish" +Output: false + +Example 3: +Input: pattern = "aaaa", str = "dog cat cat dog" +Output: false + +Example 4: +Input: pattern = "abba", str = "dog dog dog dog" +Output: false +Notes: +You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space. +Reference: https://leetcode.com/problems/word-pattern/description/ +""" +def word_pattern(pattern, str): + dict = {} + set_value = set() + list_str = str.split() + if len(list_str) != len(pattern): + return False + for i in range(len(pattern)): + if pattern[i] not in dict: + if list_str[i] in set_value: + return False + dict[pattern[i]] = list_str[i] + set_value.add(list_str[i]) + else: + if dict[pattern[i]] != list_str[i]: + return False + return True diff --git a/algorithms/set/__init__.py b/algorithms/set/__init__.py new file mode 100644 index 000000000..534e5de48 --- /dev/null +++ b/algorithms/set/__init__.py @@ -0,0 +1 @@ +from .find_keyboard_row import * diff --git a/algorithms/set/find_keyboard_row.py b/algorithms/set/find_keyboard_row.py new file mode 100644 index 000000000..e00e3683d --- /dev/null +++ b/algorithms/set/find_keyboard_row.py @@ -0,0 +1,26 @@ +""" +Given a List of words, return the words that can be typed using letters of +alphabet on only one row's of American keyboard. + +For example: +Input: ["Hello", "Alaska", "Dad", "Peace"] +Output: ["Alaska", "Dad"] + +Reference: https://leetcode.com/problems/keyboard-row/description/ +""" +def find_keyboard_row(words): + """ + :type words: List[str] + :rtype: List[str] + """ + keyboard = [ + set('qwertyuiop'), + set('asdfghjkl'), + set('zxcvbnm'), + ] + result = [] + for word in words: + for key in keyboard: + if set(word.lower()).issubset(key): + result.append(word) + return result diff --git a/tests/test_map.py b/tests/test_map.py index 5786803e9..aaff34a98 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -1,6 +1,9 @@ from algorithms.map import ( HashTable, ResizableHashTable, - Node, SeparateChainingHashTable + Node, SeparateChainingHashTable, + word_pattern, + is_isomorphic, + is_anagram ) import unittest @@ -147,6 +150,28 @@ def test_get_none_if_key_missing_and_hash_collision(self): self.assertEqual(None, m.get(11)) +class TestWordPattern(unittest.TestCase): + def test_word_pattern(self): + self.assertTrue(word_pattern("abba", "dog cat cat dog")) + self.assertFalse(word_pattern("abba", "dog cat cat fish")) + self.assertFalse(word_pattern("abba", "dog dog dog dog")) + self.assertFalse(word_pattern("aaaa", "dog cat cat dog")) + + +class TestIsSomorphic(unittest.TestCase): + def test_is_isomorphic(self): + self.assertTrue(is_isomorphic("egg", "add")) + self.assertFalse(is_isomorphic("foo", "bar")) + self.assertTrue(is_isomorphic("paper", "title")) + + +class TestIsAnagram(unittest.TestCase): + def test_is_anagram(self): + self.assertTrue(is_anagram("anagram", "nagaram")) + self.assertFalse(is_anagram("rat", "car")) + + + if __name__ == "__main__": unittest.main() diff --git a/tests/test_set.py b/tests/test_set.py new file mode 100644 index 000000000..37aea6f2a --- /dev/null +++ b/tests/test_set.py @@ -0,0 +1,10 @@ +from algorithms.set import ( + find_keyboard_row +) + +import unittest + +class TestFindKeyboardRow(unittest.TestCase): + def test_find_keyboard_row(self): + self.assertEqual(["Alaska", "Dad"], + find_keyboard_row(["Hello", "Alaska", "Dad", "Peace"])) From 48f287aff940b7f87bfbb0ac42bcd04bbf2372c8 Mon Sep 17 00:00:00 2001 From: Rick Nickerson Date: Wed, 15 Aug 2018 05:48:53 -0700 Subject: [PATCH 111/302] edited Contributing.md to add 'doc_xxx' (#392) Included language inviting contributors to improve documentation. --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 380bd3d64..3ccd4eb6c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,6 +13,7 @@ agree to abide by the [Code of Conduct](CODE_OF_CONDUCT.md). * add_XXX if you will add new algorithms or data structures. * fix_XXX if you will fixe a bug on a certain algorithm or data structure. * test_XXX if you wrote a test/s. + * doc_XXX if you added to or edited documentation. You may contribute by: - implementing new algorithms in the repo. Be sure to keep it under @@ -23,6 +24,7 @@ it doesn't fall under any section. Make sure that your implementation works. - finding and fixing bugs. - adding examples to explain the algorithms better. - adding test cases. +- improving documentation. ## Pull Requests Push to your fork and [submit a pull request][pr]. From 416edfc018d94660091c930af7bbd6f808574873 Mon Sep 17 00:00:00 2001 From: Rick Nickerson Date: Wed, 15 Aug 2018 05:50:08 -0700 Subject: [PATCH 112/302] Docs (#391) * add docs template * add logo * create documentation template --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 934100148..4d4cbb372 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) From 763221d7bdd925da7a7285f9d88596dd8e546fb5 Mon Sep 17 00:00:00 2001 From: "Tony.Chen" Date: Wed, 15 Aug 2018 20:51:29 +0800 Subject: [PATCH 113/302] fix graph/find_shortest_path (#389) --- algorithms/graph/find_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/graph/find_path.py b/algorithms/graph/find_path.py index 5008da05a..d1716c04f 100644 --- a/algorithms/graph/find_path.py +++ b/algorithms/graph/find_path.py @@ -43,7 +43,7 @@ def find_shortest_path(graph, start, end, path=[]): shortest = None for node in graph[start]: if node not in path: - newpath = find_shortest_path(graph, start, end, path) + newpath = find_shortest_path(graph, node, end, path) if newpath: if not shortest or len(newpath) < len(shortest): shortest = newpath From e6df88755e27825fee34197ca33284bf2395cbb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Redoul=C3=A8s?= Date: Sun, 19 Aug 2018 02:23:46 +0200 Subject: [PATCH 114/302] Doc fr (#394) * added french translation Added a french translation for the readme, the contributing and modified the other readme in order to add the link to the french doc * added a french translation for the code of conduct added a french translation for the code of conduct * minor typo edit * Added an link in the readme added a link to the french translation of the readme * added link to french doc added the link to the french doc in the readme * link edit the french contributing page now links to the french version of the code of conduct --- CODE_OF_CONDUCT_FR.md | 47 ++++++ CONTRIBUTING_FR.md | 65 ++++++++ README.md | 2 +- README_CN.md | 2 +- README_FR.md | 374 ++++++++++++++++++++++++++++++++++++++++++ README_GE.md | 2 +- README_JP.md | 2 +- README_KR.md | 2 +- README_PTBR.md | 2 +- 9 files changed, 492 insertions(+), 6 deletions(-) create mode 100644 CODE_OF_CONDUCT_FR.md create mode 100644 CONTRIBUTING_FR.md create mode 100644 README_FR.md diff --git a/CODE_OF_CONDUCT_FR.md b/CODE_OF_CONDUCT_FR.md new file mode 100644 index 000000000..5f870ced1 --- /dev/null +++ b/CODE_OF_CONDUCT_FR.md @@ -0,0 +1,47 @@ +# Code de conduite à l'attention des contributeurs + +## Notre engagement + +Dans le but de favoriser un environnement ouvert et accueillant, nous nous engageons à faire de la participation à ce projet et à cette communauté une expérience sans harcèlement, peu importe l'âge, la taille, le handicap, l'origine ethnique, l'identité et l'expression sexuelle, le niveau d'expérience, la nationalité, l'apparence personnelle, la race, la religion ou l'identité et l'orientation sexuelles. + +## Nos normes + +Voici quelques exemples de comportements qui contribuent à créer un environnement positif : + +* Utiliser un langage accueillant et inclusif +* Être respectueux des différents points de vue et expériences. +* Accepter dignement les critiques constructives +* Se concentrer sur ce qu'il y a de mieux pour la communauté. +* Faire preuve d'empathie envers les autres membres de la communauté. + +Voici quelques exemples de comportements inacceptables de la part des participants : + +* Le recours à un langage ou à des images de nature sexuelle et une attention ou des avances sexuelles mal venues. +* Trolling, commentaires désobligeants ou insultants et attaques personnelles ou politiques. +* Harcelement public ou privé +* Publier les informations privées d'autres personnes, telles qu'une adresse physique ou électronique, sans autorisation explicite. +* Tout autre comportement qui pourrait raisonnablement être considéré comme inapproprié dans un cadre professionnel. + + +## Nos responsabilités + +Les mainteneurs de projet sont responsables de clarifier les normes de comportement acceptable et on s'attend à ce qu'ils prennent des mesures correctives appropriées et équitables en réponse à tout cas de comportement inacceptable. + +Les mainteneurs de projet ont le droit et la responsabilité de supprimer, éditer ou rejeter les commentaires, les engagements, le code, les modifications wiki, les problèmes et autres contributions qui ne sont pas alignés sur ce code de conduite, ou d'interdire temporairement ou définitivement tout contributeur pour d'autres comportements qu'ils jugent inappropriés, menaçants, offensants ou nuisibles. + +## Champ d'application + +Le présent Code de conduite s'applique à la fois dans les espaces du projet et dans les espaces publics lorsqu'une personne représente le projet ou sa communauté. Les exemples de représentation d'un projet ou d'une communauté comprennent l'utilisation d'une adresse électronique officielle du projet, l'affichage par l'intermédiaire d'un compte officiel des médias sociaux ou le fait d'agir en tant que représentant désigné lors d'un événement en ligne ou hors ligne. La représentation d'un projet peut être définie et clarifiée par les responsables du projet. + +## Exécution + +Les cas de comportement abusif, de harcèlement ou d'autres comportements inacceptables peuvent être signalés en contactant l'équipe du projet à kwk236@gmail.com. L'équipe de projet examinera et enquêtera sur toutes les plaintes et répondra d'une manière qu'elle jugera appropriée aux circonstances. L'équipe de projet est tenue de respecter la confidentialité à l'égard du déclarant d'un incident. D'autres détails sur des politiques d'application spécifiques peuvent être affichés séparément. + +Les mainteneurs de projet qui ne suivent pas ou n'appliquent pas le Code de conduite de bonne foi peuvent faire face à des répercussions temporaires ou permanentes déterminées par d'autres membres de la direction du projet. + +## Attribution + +Le présent Code de conduite est une adaptation de la[Contributor Covenant][homepage], version 1.4, disponible à [http://contributor-covenant.org/version/1/4][version] + +[page principale]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING_FR.md b/CONTRIBUTING_FR.md new file mode 100644 index 000000000..9fe4bef95 --- /dev/null +++ b/CONTRIBUTING_FR.md @@ -0,0 +1,65 @@ +# Contribuer + +Nous aimons les contributions (sous la forme de pull requests). En contribuant à ce repertoire, vous acceptez de suivre les +règles du [Code de conduite](CODE_OF_CONDUCT_FR.md). + +## Mise en route + +* Dans un premier temps [forkez][fork] le repertoire puis clonez le grâce à la commande: + + git clone git@github.com:votre-pseudo-github/algorithms.git + +* Ensuite, créez une nouvelle branche dans laquelle vous effectuerez vos changements. For example: + * add_XXX si vous allez ajouter de nouveaux algorithmes ou de nouvelles structures de données. + * fix_XXX si vous allez corriger un bogue sur un certain algorithme ou structure de données. + * test_XXX si vous avez écrit un ou des tests. + * doc_XXX si vous avez ajouté ou édité de la documentation. + +Vous pouvez contribuer en : +- implémenter un nouvel algorithme dans ce repertoire. Faites bien attention à +le mettre dans la bonne section (i.e. [array](array), [dp](dp), etc). Vous pouvez créer une nouvelle +section si besoin. Assurez-vous que votre implémentation fonctionne, +- optimisant et en améliorant les algorithmes déjà présents, +- ajoutant de nouvelles solutions aux problèmes, +- trouvant et corrigeant des bogues, +- ajoutant des exemples afin de mieux expliquer le fonctionnement des algorithmes, +- ajoutant des tests, +- améliorant la documentation. + +## Pull Requests +Poussez votre fork sur git et [soumettez une nouvelle pull request][pr]. +Nous examinerons et pourrons suggérer des changements, des améliorations ou des solutions de rechange. +Pour faciliter l'acceptation, vous pouvez vérifier que : + +* tous les algorithmes doivent être écrits en **Python 3**, +(il reste encore quelques algorithmes écrits en _Python 2_. Vous pouvez commencer par convertir ces +[derniers][issue120] vers du _Python 3_), +* écrire un code propre et compréhensible, +* commenter correctement le code et expliquer brièvement ce que l'algorithme fait dans la [documentation][docstr], +* vous pouvez également expliquer le résultat à l'aide d'un exemple simple. +* essayer d'écrire quelques tests pour les algorithmes, +* écrire un [message de soumission (commit) clair][commit]. + + +## Problèmes +Soumettez une [nouveau issue][newissue] s'il y a un algorithme à ajouter, ou si un bogue a été trouvé dans un algorithme existant. Avant d'en soumettre une nouvelle, veuillez passer en revue les [issues existantes][issues] afin d'éviter de créer des doublons. Envisagez également de résoudre des issues actuellement ouvertes ou de contribuer à la discussion sur une issue. + +## Collaborateurs +Vous pouvez demander de l'aide ou des éclaircissements aux collaborateurs. +[Keon Kim](https://github.com/keon) + +[Rahul Goswami](https://github.com/goswami-rahul) + +[Ankit Agarwal](https://github.com/ankit167) + +[Hai Hoang Dang](https://github.com/danghai) + +[Saad](https://github.com/SaadBenn) + +[fork]: https://help.github.com/articles/fork-a-repo/ +[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings +[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[pr]: https://github.com/keon/algorithms/compare/ +[newissue]: https://github.com/keon/algorithms/issues/new +[issue120]: https://github.com/keon/algorithms/issues/120 +[issues]: https://github.com/keon/algorithms/issues/ diff --git a/README.md b/README.md index 4d4cbb372..7ed869497 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) +English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_CN.md b/README_CN.md index 4dc5cfcc7..ee405457a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@

-[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) +[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_FR.md b/README_FR.md new file mode 100644 index 000000000..bfe2f905a --- /dev/null +++ b/README_FR.md @@ -0,0 +1,374 @@ +

+ +English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) + +[![Version PyPI](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) +[![Contributeurs open source](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + +Structures de données adaptées au Python et algorithmes +======================================================= + +Exemples simples et optimisés d'implémentations de structures de données et d'algorithmes en Python 3. + +## Contribuer +Merci de votre intérêt à contribuer ! Il y a plusieurs façons de contribuer à ce projet. [Commencez ici](CONTRIBUTING_FR.md) + +## Tests + +### Utilisation de unittest +Pour lancer tous les tests, saisissez la commande suivante : + $ python3 -m unittest discover tests + +Pour lancer des tests particuliers vous pouvez procéder comme suit(Ex: sort): + + $ python3 -m unittest tests.test_sort + +### Utilisation de pytest +Pour lancer tous les tests, saisissez la commande suivante : + + $ python3 -m pytest tests + +## Installation +Si vous voulez utiliser les algorithmes sous forme de paquet dans votre code, il suffit de faire ceci : + + $ pip3 install algorithms + +Vous pouvez tester votre installation en créant un fichier python : (Ex: utilisation de `merge_sort` dans `sort`) + +```python3 +from algorithms.sort import merge_sort + +if __name__ == "__main__": + my_list = [1, 8, 3, 5, 6] + my_list = merge_sort(my_list) + print(my_list) +``` + +## Désinstallation +Si vous voulez désinstaller le paquet algorithms, il suffit de procéder comme suit : + + $ pip3 uninstall -y algorithms + +## Liste des algorithmes + +- [arrays](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) + - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros](algorithms/arrays/move_zeros.py) + - [n_sum](algorithms/arrays/n_sum.py) +- [backtrack](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit](algorithms/bit) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_difference](algorithms/bit/find_difference.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) + - [binary_gap](algorithms/bit/binary_gap.py) +- [calculator](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) + - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) + - [word_pattern](algorithms/map/word_pattern.py) + - [is_isomorphic](algorithms/map/is_isomorphic.py) + - [is_anagram](algorithms/map/is_anagram.py) +- [maths](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) + - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurance](algorithms/search/first_occurance.py) + - [last_occurance](algorithms/search/last_occurance.py) + - [linear_search](algorithms/search/linear_search.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) + - [next_greatest_letter](algorithms/search/next_greatest_letter.py) +- [set](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) + - [find_keyboard_row](algorithms/set/find_keyboard_row.py) +- [sort](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) + - [bogo_sort](algorithms/sort/bogo_sort.py) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [top_sort](algorithms/sort/top_sort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) + - [unique_morse](algorithms/strings/unique_morse.py) + - [judge_circle](algorithms/strings/judge_circle.py) + - [strong_password](algorithms/strings/strong_password.py) + - [caesar_cipher](algorithms/strings/caesar_cipher.py) + - [contain_string](algorithms/strings/contain_string.py) + - [count_binary_substring](algorithms/strings/count_binary_substring.py) + - [repeat_string](algorithms/strings/repeat_string.py) + - [min_distance](algorithms/strings/min_distance.py) + - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) + - [rotate](algorithms/strings/rotate.py) + - [first_unique_char](algorithms/strings/first_unique_char.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) +- [tree](algorithms/tree) + - [bst](algorithms/tree/tree/bst) + - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bintree2list](algorithms/tree/bintree2list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [unix](algorithms/unix) + - [path](algorithms/unix/path/) + - [join_with_slash](algorithms/unix/path/join_with_slash.py) + - [full_path](algorithms/unix/path/full_path.py) + - [split](algorithms/unix/path/split.py) + - [simplify_path](algorithms/unix/path/simplify_path.py) +- [union-find](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) +- [machine-learning](algorithms/machine-learning) + - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) + +## Contributeurs +Ce répertoire est maintenu par + +* [Keon Kim](https://github.com/keon) +* [Rahul Goswami](https://github.com/goswami-rahul) +* [Christian Bender](https://github.com/christianbender) +* [Ankit Agarwal](https://github.com/ankit167) +* [Hai Hoang Dang](https://github.com/danghai) +* [Saad](https://github.com/SaadBenn) + +Et merci à[tous les contributeurs](https://github.com/keon/algorithms/graphs/contributors) +qui a aidé à construire le répertoire. diff --git a/README_GE.md b/README_GE.md index be908bc28..782c494c0 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) +[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_JP.md b/README_JP.md index c0a56c2bf..b5fff7bc9 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_KR.md b/README_KR.md index efd98483e..cf0912506 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) | [Français](README_FR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_PTBR.md b/README_PTBR.md index 2870a1546..efe3b1ba0 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português | [Français](README_FR.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) From 02b6e367b1af6e02d8c7f897a15ed08510fbdfd3 Mon Sep 17 00:00:00 2001 From: Arnav Borborah Date: Mon, 3 Sep 2018 16:38:29 -0400 Subject: [PATCH 115/302] No need to create a variable for length (#399) --- algorithms/search/linear_search.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/algorithms/search/linear_search.py b/algorithms/search/linear_search.py index da4d9b93c..cf57fcf97 100644 --- a/algorithms/search/linear_search.py +++ b/algorithms/search/linear_search.py @@ -5,8 +5,7 @@ # def linear_search(array, query): - length = len(array) - for i in range(length): + for i in range(len(array)): if array[i] == query: return i From cdae90c04847db53a60a85a6be398b412574be7e Mon Sep 17 00:00:00 2001 From: jesili <35131514+jesili@users.noreply.github.com> Date: Tue, 4 Sep 2018 16:04:10 +0800 Subject: [PATCH 116/302] Update is_balanced.py (#398) fixed a little bug --- algorithms/tree/is_balanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/tree/is_balanced.py b/algorithms/tree/is_balanced.py index 69a420e83..7d3297d32 100644 --- a/algorithms/tree/is_balanced.py +++ b/algorithms/tree/is_balanced.py @@ -13,7 +13,7 @@ def get_depth(root): return 0 left = get_depth(root.left) right = get_depth(root.right) - if abs(left-right) > 1: + if abs(left-right) > 1 or left == -1 or right == -1: return -1 return 1 + max(left, right) From f5fec1231f5c6212fc5c5faf7e42780da721fdd9 Mon Sep 17 00:00:00 2001 From: Inno Fang Date: Tue, 4 Sep 2018 16:41:55 +0800 Subject: [PATCH 117/302] fix sort/radix_sort (#395) (#397) * fix sort/radix_sort (#395) * Add a new line for radix_sort.py --- algorithms/sort/radix_sort.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/algorithms/sort/radix_sort.py b/algorithms/sort/radix_sort.py index dd4113d05..89a2dbcc9 100644 --- a/algorithms/sort/radix_sort.py +++ b/algorithms/sort/radix_sort.py @@ -1,24 +1,21 @@ """ radix sort -complexity: O(nk) . n is the size of input list and k is the digit length of the number +complexity: O(nk + n) . n is the size of input list and k is the digit length of the number """ def radix_sort(arr, simulation=False): - is_done = False position = 1 + max_number = max(arr) iteration = 0 if simulation: - print("iteration",iteration,":",*arr) + print("iteration", iteration, ":", *arr) - while not is_done: + while position < max_number: queue_list = [list() for _ in range(10)] - is_done = True for num in arr: digit_number = num // position % 10 queue_list[digit_number].append(num) - if is_done and digit_number > 0: - is_done = False index = 0 for numbers in queue_list: @@ -28,7 +25,8 @@ def radix_sort(arr, simulation=False): if simulation: iteration = iteration + 1 - print("iteration",iteration,":",*arr) + print("iteration", iteration, ":", *arr) position *= 10 return arr + \ No newline at end of file From 4f8ccdd7dd3152a02e43fab33face9ec26b16d2e Mon Sep 17 00:00:00 2001 From: Arnav Borborah Date: Wed, 5 Sep 2018 15:00:49 -0400 Subject: [PATCH 118/302] Initial check at beginning of function is useless (#403) --- algorithms/search/search_rotate.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/algorithms/search/search_rotate.py b/algorithms/search/search_rotate.py index ade027082..a92a15ee3 100644 --- a/algorithms/search/search_rotate.py +++ b/algorithms/search/search_rotate.py @@ -37,9 +37,6 @@ Recursion helps you understand better the above algorithm explanation """ def search_rotate(array, val): - if not array: - return -1 - low, high = 0, len(array) - 1 while low <= high: mid = (low + high) // 2 From e0cc8c339e67f31cea92a57eda458387e6f82b09 Mon Sep 17 00:00:00 2001 From: Anoubhav Agarwaal <38296352+anoubhav@users.noreply.github.com> Date: Fri, 7 Sep 2018 18:37:58 +0530 Subject: [PATCH 119/302] Update is_sorted.py (#402) * Update is_sorted.py 1)The first 2 return statements have been changed to break statements. This ensures that the code after the first for loop is executed. Previously it would never execute the latter part. 2)The second append statement should add elements to stack and not storage_stack. Try the test case [3,4,7,8,5,6]. The program returns True. It should return False. * Add test for is_sorted --- algorithms/stack/is_sorted.py | 6 +++--- tests/test_stack.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/algorithms/stack/is_sorted.py b/algorithms/stack/is_sorted.py index 8824dfa95..0a69d83f9 100644 --- a/algorithms/stack/is_sorted.py +++ b/algorithms/stack/is_sorted.py @@ -13,15 +13,15 @@ def is_sorted(stack): storage_stack = [] for i in range(len(stack)): if len(stack) == 0: - return True + break first_val = stack.pop() if len(stack) == 0: - return True + break second_val = stack.pop() if first_val < second_val: return False storage_stack.append(first_val) - storage_stack.append(second_val) + stack.append(second_val) # Backup stack for i in range(len(storage_stack)): diff --git a/tests/test_stack.py b/tests/test_stack.py index d04b27f14..78822bc17 100644 --- a/tests/test_stack.py +++ b/tests/test_stack.py @@ -25,6 +25,7 @@ def test_is_sorted(self): # Test case: bottom [6, 3, 5, 1, 2, 4] top self.assertFalse(is_sorted([6, 3, 5, 1, 2, 4])) self.assertTrue(is_sorted([1, 2, 3, 4, 5, 6])) + self.assertFalse(is_sorted([3, 4, 7, 8, 5, 6])) def test_remove_min(self): # Test case: bottom [2, 8, 3, -6, 7, 3] top From 3f9aa455eb0888943bac337054cd0d317f3f4418 Mon Sep 17 00:00:00 2001 From: Oerd Cukalla Date: Thu, 27 Sep 2018 10:49:53 +0200 Subject: [PATCH 120/302] Update links in `Readme.md` (#411) Fixed broken links to algorithms in `Readme.md` --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7ed869497..6d5b74734 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,10 @@ If you want to uninstall algorithms, it is as simple as: - [n_sum](algorithms/arrays/n_sum.py) - [backtrack](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) + - [add_operators](algorithms/backtrack/add_operators.py) - [anagram](algorithms/backtrack/anagram.py) - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - [combination_sum](algorithms/backtrack/combination_sum.py) - - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) - [factor_combinations](algorithms/backtrack/factor_combinations.py) - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) @@ -142,7 +142,7 @@ If you want to uninstall algorithms, it is as simple as: - [fibonacci](algorithms/dp/fib.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) + - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) - [clone_graph](algorithms/graph/clone_graph.py) - [cycle_detection](algorithms/graph/cycle_detection.py) - [find_all_cliques](algorithms/graph/find_all_cliques.py) @@ -221,8 +221,8 @@ If you want to uninstall algorithms, it is as simple as: - [zigzagiterator](algorithms/queues/zigzagiterator.py) - [search](algorithms/search) - [binary_search](algorithms/search/binary_search.py) - - [first_occurance](algorithms/search/first_occurance.py) - - [last_occurance](algorithms/search/last_occurance.py) + - [first_occurrence](algorithms/search/first_occurrence.py) + - [last_occurrence](algorithms/search/last_occurrence.py) - [linear_search](algorithms/search/linear_search.py) - [search_insert](algorithms/search/search_insert.py) - [two_sum](algorithms/search/two_sum.py) @@ -269,7 +269,7 @@ If you want to uninstall algorithms, it is as simple as: - [is_sorted](algorithms/stack/is_sorted.py) - [strings](algorithms/strings) - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) + - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) - [strip_url_params](algorithms/strings/strip_url_params.py) - [validate_coordinates](algorithms/strings/validate_coordinates.py) - [domain_extractor](algorithms/strings/domain_extractor.py) @@ -304,8 +304,8 @@ If you want to uninstall algorithms, it is as simple as: - [first_unique_char](algorithms/strings/first_unique_char.py) - [repeat_substring](algorithms/strings/repeat_substring.py) - [tree](algorithms/tree) - - [bst](algorithms/tree/tree/bst) - - [array2bst](algorithms/tree/bst/array2bst.py) + - [bst](algorithms/tree/bst) + - [array_to_bst](algorithms/tree/bst/array_to_bst.py) - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - [delete_node](algorithms/tree/bst/delete_node.py) @@ -334,7 +334,7 @@ If you want to uninstall algorithms, it is as simple as: - [add_and_search](algorithms/tree/trie/add_and_search.py) - [trie](algorithms/tree/trie/trie.py) - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bintree2list](algorithms/tree/bintree2list.py) + - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) - [deepest_left](algorithms/tree/deepest_left.py) - [invert_tree](algorithms/tree/invert_tree.py) - [is_balanced](algorithms/tree/is_balanced.py) From 30ca4ae2e6133bbfa0120feeda2066647132a19e Mon Sep 17 00:00:00 2001 From: jesili <35131514+jesili@users.noreply.github.com> Date: Sat, 29 Sep 2018 03:07:53 +0800 Subject: [PATCH 121/302] Update is_symmetric.py (#396) --- algorithms/tree/is_symmetric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/tree/is_symmetric.py b/algorithms/tree/is_symmetric.py index 3aff3cfd2..0fd56b9aa 100644 --- a/algorithms/tree/is_symmetric.py +++ b/algorithms/tree/is_symmetric.py @@ -46,7 +46,7 @@ def is_symmetric_iterative(root): return False if left.val == right.val: stack.append([left.left, right.right]) - stack.append([left.right, right.right]) + stack.append([left.right, right.left]) else: return False return True From 89aabdeead94821e92c2188610ef9c3dd7447cea Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Wed, 3 Oct 2018 11:36:31 +0530 Subject: [PATCH 122/302] Optimize bubbe sort (#417) * Optimize bubbe sort - as after each step of 'outer-loop', one number reaches to its right position. Thus inner loop does not need to run for 'n' times in every cycle of 'outer-loop'. * Followed PEP for PR #417 --- algorithms/sort/bubble_sort.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/algorithms/sort/bubble_sort.py b/algorithms/sort/bubble_sort.py index 76c9816fa..84f406795 100644 --- a/algorithms/sort/bubble_sort.py +++ b/algorithms/sort/bubble_sort.py @@ -20,10 +20,11 @@ def swap(i, j): iteration = 0 if simulation: print("iteration",iteration,":",*arr) - + x = -1 while swapped: swapped = False - for i in range(1, n): + x = x + 1 + for i in range(1, n-x): if arr[i - 1] > arr[i]: swap(i - 1, i) swapped = True From 62a3ba2b0be48e9ed5f6de5ec831c30f0824f53a Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Mon, 8 Oct 2018 08:39:06 +0530 Subject: [PATCH 123/302] add Euler's Totient function (#421) * add Euler's Totient function * add link to Euler's totient function in README --- README.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/euler_totient.py | 18 ++++++++++++++++++ tests/test_maths.py | 21 ++++++++++++++++++--- 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 algorithms/maths/euler_totient.py diff --git a/README.md b/README.md index 6d5b74734..aecd53b6d 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ If you want to uninstall algorithms, it is as simple as: - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) + - [euler_totient](algorithms/maths/euler_totient.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 177fed31d..7a3fb7b00 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -1,5 +1,6 @@ from .base_conversion import * from .decimal_to_binary_ip import * +from .euler_totient import * from .extended_gcd import * from .factorial import * from .gcd import * diff --git a/algorithms/maths/euler_totient.py b/algorithms/maths/euler_totient.py new file mode 100644 index 000000000..047b72827 --- /dev/null +++ b/algorithms/maths/euler_totient.py @@ -0,0 +1,18 @@ +""" +Euler's totient function, also known as phi-function ϕ(n), +counts the number of integers between 1 and n inclusive, +which are coprime to n. +(Two numbers are coprime if their greatest common divisor (GCD) equals 1). +""" +def euler_totient(n): + """Euler's totient function or Phi function. + Time Complexity: O(sqrt(n)).""" + result = n; + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + while n % i == 0: + n //= i + result -= result // i + if n > 1: + result -= result // n; + return result; diff --git a/tests/test_maths.py b/tests/test_maths.py index 2499a4f88..0777f9ab3 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,6 +1,7 @@ from algorithms.maths import ( int_to_base, base_to_int, decimal_to_binary_ip, + euler_totient, extended_gcd, factorial, factorial_recur, gcd, lcm, @@ -36,8 +37,8 @@ def test_base_to_int(self): self.assertEqual(5, base_to_int("101", 2)) self.assertEqual(0, base_to_int("0", 2)) self.assertEqual(255, base_to_int("FF", 16)) - - + + class TestDecimalToBinaryIP(unittest.TestCase): """ Test for the file decimal_to_binary_ip.py @@ -55,6 +56,21 @@ def test_decimal_to_binary_ip(self): decimal_to_binary_ip("192.168.0.1")) +class TestEulerTotient(unittest.TestCase): + """[summary] + Test for the file euler_totient.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_euler_totient(self): + self.assertEqual(4, euler_totient(8)) + self.assertEqual(12, euler_totient(21)) + self.assertEqual(311040, euler_totient(674614)) + self.assertEqual(2354352, euler_totient(3435145)) + + class TestExtendedGcd(unittest.TestCase): """[summary] Test for the file extended_gcd.py @@ -274,4 +290,3 @@ def test_factorial_recur(self): if __name__ == "__main__": unittest.main() - From bac3222c1dd51741887a2187ef0be10e8902c5af Mon Sep 17 00:00:00 2001 From: Rick Nickerson Date: Sun, 7 Oct 2018 20:18:42 -0700 Subject: [PATCH 124/302] PEP8 style sweep (#393) Without affecting test ratios, I have made a sweep of the Arrays algorithms, and improved style, commentary, whitespace, and some translations flatten.py -- added commentary Garage.py -- added commentary, enforced line width on existing commentary Josephus.py -- enforced commentary alignment, binary operator spacing Limit.py -- enforced binary operator spacing, enforced commentary width This function is very similar to Python array-slicing, except by value. longest_non_repeat.py -- enforced spacing style in commentary added get functions Enforced function whitespace of one carriage return merge_intervals.py -- switched docstrings so the subject exposition was in the intro and the action done by the class was under the class, cleaned up other docstrings -- this class does need a docstring, but not the mathematician's exposition. What does this object do? n_sum.py -- added whitespace around recursive call, added (TL:DR) commentary, added docstrings, added commentary identifying recursive call, enforced line width and pep8 line break style WRT parameters on newlines w/ parentheses (e.g. lines 81-84, 88-90), enforced spelling consistency in argument parameters (e.g. target/taget) plus_one.py -- removed unused variable in plus_one_v3 method, clarified opening docstring rotate.py -- added comment line 24 for intentionally unused variable, enforced whitespace guidelines between methods three_sum.py -- specified opening docstring to indicate distinct elements in solution sets top_1.py -- improved translation in commentary trimmean.py -- improved translation in commentary, removed leftover commented instrumentation --- .vscode/settings.json | 3 ++ algorithms/arrays/flatten.py | 6 +-- algorithms/arrays/garage.py | 26 ++++++++++--- algorithms/arrays/josephus.py | 4 +- algorithms/arrays/limit.py | 15 ++++---- algorithms/arrays/longest_non_repeat.py | 44 +++++++++++++++++++-- algorithms/arrays/merge_intervals.py | 19 +++++---- algorithms/arrays/missing_ranges.py | 5 +-- algorithms/arrays/n_sum.py | 51 +++++++++++++++---------- algorithms/arrays/plus_one.py | 6 +-- algorithms/arrays/rotate.py | 2 +- algorithms/arrays/three_sum.py | 4 +- algorithms/arrays/top_1.py | 13 +++++-- algorithms/arrays/trimmean.py | 12 +++--- 14 files changed, 141 insertions(+), 69 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9d17a2792 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\Python36_64\\python.exe" +} \ No newline at end of file diff --git a/algorithms/arrays/flatten.py b/algorithms/arrays/flatten.py index f2eba48fe..4133c3458 100644 --- a/algorithms/arrays/flatten.py +++ b/algorithms/arrays/flatten.py @@ -12,9 +12,9 @@ def flatten(input_arr, output_arr=None): output_arr = [] for ele in input_arr: if isinstance(ele, Iterable): - flatten(ele, output_arr) + flatten(ele, output_arr) #tail-recursion else: - output_arr.append(ele) + output_arr.append(ele) #produce the result return output_arr @@ -26,6 +26,6 @@ def flatten_iter(iterable): """ for element in iterable: if isinstance(element, Iterable): - yield from flatten_iter(element) + yield from flatten_iter(element) else: yield element diff --git a/algorithms/arrays/garage.py b/algorithms/arrays/garage.py index d590343b7..474655abd 100644 --- a/algorithms/arrays/garage.py +++ b/algorithms/arrays/garage.py @@ -34,14 +34,14 @@ def garage(initial, final): - initial = initial[::] # create a copy to prevent changes in original 'initial'. + initial = initial[::] # prevent changes in original 'initial' + seq = [] # list of each step in sequence steps = 0 - seq = [] # list of each step in sequence while initial != final: zero = initial.index(0) - if zero != final.index(0): - car_to_move = final[zero] - pos = initial.index(car_to_move) + if zero != final.index(0): # if zero isn't where it should be, + car_to_move = final[zero] # what should be where zero is, + pos = initial.index(car_to_move) # and where is it? initial[zero], initial[pos] = initial[pos], initial[zero] else: for i in range(len(initial)): @@ -51,4 +51,18 @@ def garage(initial, final): seq.append(initial[::]) steps += 1 - return steps, seq + return steps, seq + # e.g.: 4, [{0, 2, 3, 1, 4}, {2, 0, 3, 1, 4}, + # {2, 3, 0, 1, 4}, {0, 3, 2, 1, 4}] + +""" +thus: +1 2 3 0 4 -- zero = 3, true, car_to_move = final[3] = 1, + pos = initial.index(1) = 0, switched [0], [3] +0 2 3 1 4 -- zero = 0, f, initial[1] != final[1], switched 0,1 +2 0 3 1 4 -- zero = 1, t, car_to_move = final[1] = 3, + pos = initial.index(3) = 2, switched [1], [2] +2 3 0 1 4 -- zero = 2, t, car_to_move = final[2] = 2, + pos = initial.index(2) = 0, switched [0], [2] +0 3 2 1 4 -- initial == final +""" \ No newline at end of file diff --git a/algorithms/arrays/josephus.py b/algorithms/arrays/josephus.py index f77c48a5c..3d0ad2329 100644 --- a/algorithms/arrays/josephus.py +++ b/algorithms/arrays/josephus.py @@ -11,10 +11,10 @@ def josephus(int_list, skip): - skip = skip - 1 # list starts with 0 index + skip = skip - 1 # list starts with 0 index idx = 0 len_list = (len(int_list)) while len_list > 0: - idx = (skip+idx) % len_list # hash index to every 3rd + idx = (skip + idx) % len_list # hash index to every 3rd yield int_list.pop(idx) len_list -= 1 diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py index adcc57797..131d16edb 100644 --- a/algorithms/arrays/limit.py +++ b/algorithms/arrays/limit.py @@ -1,22 +1,23 @@ """ -Sometimes you need to limit array result to use. Such as you only need the value over -10 or, you need value under than 100. By use this algorithms, you can limit your array -to specific value +Sometimes you need to limit array result to use. Such as you only need the + value over 10 or, you need value under than 100. By use this algorithms, you + can limit your array to specific value -If array, Min, Max value was given, it returns array that contains values of given array -which was larger than Min, and lower than Max. You need to give 'unlimit' to use only Min -or Max. +If array, Min, Max value was given, it returns array that contains values of + given array which was larger than Min, and lower than Max. You need to give + 'unlimit' to use only Min or Max. ex) limit([1,2,3,4,5], None, 3) = [1,2,3] Complexity = O(n) """ +# tl:dr -- array slicing by value def limit(arr, min_lim = None, max_lim = None): result = [] if min_lim == None: for i in arr: - if i<= max_lim: + if i <= max_lim: result.append(i) elif max_lim == None: for i in arr: diff --git a/algorithms/arrays/longest_non_repeat.py b/algorithms/arrays/longest_non_repeat.py index 1d083fb0e..cad3d2430 100644 --- a/algorithms/arrays/longest_non_repeat.py +++ b/algorithms/arrays/longest_non_repeat.py @@ -1,6 +1,7 @@ """ Given a string, find the length of the longest substring without repeating characters. + Examples: Given "abcabcbb", the answer is "abc", which the length is 3. Given "bbbbb", the answer is "b", with the length of 1. @@ -12,7 +13,8 @@ def longest_non_repeat_v1(string): """ - Apply slide windown. + Find the length of the longest substring + without repeating characters. """ dict = {} max_length = 0 @@ -24,10 +26,9 @@ def longest_non_repeat_v1(string): max_length = max(max_length, i - j + 1) return max_length - def longest_non_repeat_v2(string): """ - Finds the length of the longest substring + Find the length of the longest substring without repeating characters. Uses alternative algorithm. """ @@ -42,3 +43,40 @@ def longest_non_repeat_v2(string): max_len = max(max_len, index - start + 1) used_char[char] = index return max_len + +# get functions of above, returning the max_len and substring +def get_longest_non_repeat_v1(string): + """ + Find the length of the longest substring + without repeating characters. + Return max_len and the substring as a tuple + """ + if string is None: + return 0 + temp = [] + max_len = 0 + for i in string: + if i in temp: + temp = [] + temp.append(i) + max_len = max(max_len, len(temp)) + return max_len, temp + +def get_longest_non_repeat_v2(string): + """ + Find the length of the longest substring + without repeating characters. + Uses alternative algorithm. + Return max_len and the substring as a tuple + """ + if string is None: + return 0 + start, max_len = 0, 0 + used_char = {} + for index, char in enumerate(string): + if char in used_char and start <= used_char[char]: + start = used_char[char] + 1 + else: + max_len = max(max_len, index - start + 1) + used_char[char] = index + return max_len, start \ No newline at end of file diff --git a/algorithms/arrays/merge_intervals.py b/algorithms/arrays/merge_intervals.py index ee9ce6053..fae4162f6 100644 --- a/algorithms/arrays/merge_intervals.py +++ b/algorithms/arrays/merge_intervals.py @@ -1,15 +1,16 @@ """ -Given a collection of intervals, merge all overlapping intervals. +In mathematics, a (real) interval is a set of real + numbers with the property that any number that lies + between two numbers in the set is also included in the set. """ class Interval: """ - In mathematics, a (real) interval is a set of real - numbers with the property that any number that lies - between two numbers in the set is also included in the set. + A set of real numbers with methods to determine if other + numbers are included in the set. + Includes related methods to merge and print interval sets. """ - def __init__(self, start=0, end=0): self.start = start self.end = end @@ -44,7 +45,7 @@ def as_list(self): @staticmethod def merge(intervals): - """ Merges two intervals into one. """ + """ Merge two intervals into one. """ out = [] for i in sorted(intervals, key=lambda i: i.start): if out and i.start <= out[-1].end: @@ -55,9 +56,7 @@ def merge(intervals): @staticmethod def print_intervals(intervals): - """ - Prints out the intervals. - """ + """ Print out the intervals. """ res = [] for i in intervals: res.append(repr(i)) @@ -65,7 +64,7 @@ def print_intervals(intervals): def merge_intervals(intervals): - """ Merges intervals in the form of list. """ + """ Merge intervals in the form of a list. """ if intervals is None: return None intervals.sort(key=lambda i: i[0]) diff --git a/algorithms/arrays/missing_ranges.py b/algorithms/arrays/missing_ranges.py index 68fcc4391..7f34bcd13 100644 --- a/algorithms/arrays/missing_ranges.py +++ b/algorithms/arrays/missing_ranges.py @@ -3,7 +3,6 @@ Ex) [3, 5] lo=1 hi=10 => answer: [(1, 2), (4, 4), (6, 10)] """ - def missing_ranges(arr, lo, hi): res = [] @@ -17,7 +16,7 @@ def missing_ranges(arr, lo, hi): res.append((start, n-1)) start = n + 1 - if start <= hi: - res.append((start, hi)) + if start <= hi: # after done iterating thru array, + res.append((start, hi)) # append remainder to list return res diff --git a/algorithms/arrays/n_sum.py b/algorithms/arrays/n_sum.py index a01348e57..da7ee3666 100644 --- a/algorithms/arrays/n_sum.py +++ b/algorithms/arrays/n_sum.py @@ -2,30 +2,32 @@ Given an array of n integers, are there elements a, b, .. , n in nums such that a + b + .. + n = target? -Find all unique triplets in the array which gives the sum of target. +Find all unique n-tuplets in the array which gives the sum of target. Example: basic: Given: - n = 4, nums = [1, 0, -1, 0, -2, 2], target = 0, + n = 4 + nums = [1, 0, -1, 0, -2, 2] + target = 0, return [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]] advanced: Given: n = 2 nums = [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]] - taget = -5 + target = -5 def sum(a, b): return [a[0] + b[1], a[1] + b[0]] - def compare(num, taget): - if num[0] < taget: + def compare(num, target): + if num[0] < target: return -1 - elif if num[0] > taget: + elif if num[0] > target: return 1 else: return 0 return [[-9, 5], [8, 4]] - because -9 + 4 = -5 +(TL:DR) because -9 + 4 = -5 """ @@ -35,24 +37,26 @@ def n_sum(n, nums, target, **kv): nums: list[object] target: object sum_closure: function, optional - Given two elements of nums, return sum of both. + Given two elements of nums, return sum of both. compare_closure: function, optional - Given one object of nums and target, return one of -1, 1, or 0. + Given one object of nums and target, return -1, 1, or 0. same_closure: function, optional - Given two object of nums, return bool. + Given two object of nums, return bool. return: list[list[object]] Note: - 1. type of sum_closure's return should be same as type of compare_closure's first param + 1. type of sum_closure's return should be same + as type of compare_closure's first param """ def sum_closure_default(a, b): return a + b - def compare_closure_default(num, taget): - if num < taget: + def compare_closure_default(num, target): + """ above, below, or right on? """ + if num < target: return -1 - elif num > taget: + elif num > target: return 1 else: return 0 @@ -61,7 +65,7 @@ def same_closure_default(a, b): return a == b def n_sum(n, nums, target): - if n == 2: + if n == 2: # want answers with only 2 terms? easy! results = two_sum(nums, target) else: results = [] @@ -70,12 +74,19 @@ def n_sum(n, nums, target): if prev_num is not None and \ same_closure(prev_num, num): continue + prev_num = num - n_minus1_results = n_sum(n - 1, - nums[index + 1:], - target - num) - n_minus1_results = append_elem_to_each_list(num, - n_minus1_results) + n_minus1_results = ( + n_sum( # recursive call + n - 1, # a + nums[index + 1:], # b + target - num # c + ) # x = n_sum( a, b, c ) + ) # n_minus1_results = x + + n_minus1_results = ( + append_elem_to_each_list(num, n_minus1_results) + ) results += n_minus1_results return union(results) diff --git a/algorithms/arrays/plus_one.py b/algorithms/arrays/plus_one.py index d5bf347f6..f63aafaea 100644 --- a/algorithms/arrays/plus_one.py +++ b/algorithms/arrays/plus_one.py @@ -1,8 +1,8 @@ """ Given a non-negative number represented as an array of digits, -plus one to the number. +adding one to each numeral. -The digits are stored such that the most significant +The digits are stored big-endian, such that the most significant digit is at the head of the list. """ @@ -41,7 +41,7 @@ def plus_one_v2(digits): def plus_one_v3(num_arr): - for idx, digit in reversed(list(enumerate(num_arr))): + for idx in reversed(list(enumerate(num_arr))): num_arr[idx] = (num_arr[idx] + 1) % 10 if num_arr[idx]: return num_arr diff --git a/algorithms/arrays/rotate.py b/algorithms/arrays/rotate.py index d90035b58..974b511f3 100644 --- a/algorithms/arrays/rotate.py +++ b/algorithms/arrays/rotate.py @@ -21,7 +21,7 @@ def rotate_v1(array, k): """ array = array[:] n = len(array) - for i in range(k): + for i in range(k): # unused variable is not a problem temp = array[n - 1] for j in range(n-1, 0, -1): array[j] = array[j - 1] diff --git a/algorithms/arrays/three_sum.py b/algorithms/arrays/three_sum.py index 524b83edd..ccf3d2669 100644 --- a/algorithms/arrays/three_sum.py +++ b/algorithms/arrays/three_sum.py @@ -1,6 +1,6 @@ """ -Given an array S of n integers, are there elements a, b, c in S -such that a + b + c = 0? +Given an array S of n integers, are there three distinct elements +a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: The solution set must not contain duplicate triplets. diff --git a/algorithms/arrays/top_1.py b/algorithms/arrays/top_1.py index dea9aa2f9..71ac6b042 100644 --- a/algorithms/arrays/top_1.py +++ b/algorithms/arrays/top_1.py @@ -1,11 +1,15 @@ """ -this algorithms receive array and check most_frequent_value(a.k.a mode). Also, sometimes it can be have numerous most_frequent_value, -so this funtion returns list. This result can be used as finding representative value on array. +This algorithm receives an array and returns most_frequent_value +Also, sometimes it is possible to have multiple 'most_frequent_value's, +so this function returns a list. This result can be used to find a +representative value in an array. -This algorithms get array, and make dictionary of it, find most frequent count, and make result list. +This algorithm gets an array, makes a dictionary of it, + finds the most frequent count, and makes the result list. -For example) top_1([1, 1, 2, 2, 3, 4]) will return [1, 2] +For example: top_1([1, 1, 2, 2, 3, 4]) will return [1, 2] +(TL:DR) Get mathematical Mode Complexity: O(n) """ def top_1(arr): @@ -30,3 +34,4 @@ def top_1(arr): continue return result + \ No newline at end of file diff --git a/algorithms/arrays/trimmean.py b/algorithms/arrays/trimmean.py index 4cea0db74..3d330a0e3 100644 --- a/algorithms/arrays/trimmean.py +++ b/algorithms/arrays/trimmean.py @@ -1,9 +1,12 @@ """ -When make reliable means, we need to neglect best and worst value. For example, when making average score on athletes we need this option. -So, this algorithms, fix some percentage to neglect when making mean. For example, if you suggest 20%, it will neglect best 10% value, and -worst 10% value. +When make reliable means, we need to neglect best and worst values. +For example, when making average score on athletes we need this option. +So, this algorithm affixes some percentage to neglect when making mean. +For example, if you suggest 20%, it will neglect the best 10% of values +and the worst 10% of values. -This algorithm gets array and percentage to neglect. After sorted, if index of array is larger or smaller or wanted ratio, we don't +This algorithm takes an array and percentage to neglect. After sorted, +if index of array is larger or smaller than desired ratio, we don't compute it. Compleity: O(n) @@ -18,5 +21,4 @@ def trimmean(arr, per): arr = arr[neg_val:len(arr)-neg_val] for i in arr: cal_sum += i - #print(cal_sum, len(arr)) return cal_sum/len(arr) From 8694de54ad1efdc0c1ee5823e46cdc1370c9f2ec Mon Sep 17 00:00:00 2001 From: Anton Perez <2671616+krimvp@users.noreply.github.com> Date: Wed, 17 Oct 2018 01:29:38 +0200 Subject: [PATCH 125/302] Fix array plus one v3 (#432) * Fixes code for linkedlist/copy_random_pointer - Fixes the code (was previously commented) by uncommenting it and implementing the missing class that was referenced - Creates 2 test cases for both solutions in the code * Fix tests for arrays/plus_one - There was an issue while trying to access an index in a for loop within the array package (plus_one_v3() function) - idx was a tuple since it was being created as an enumerate(list) but it was being used as a simple index to access the list. - Changes the idx to access the element of the tuple that is the actual index (not the value) * Reformat linkedlist copy_random_pointer - Remove classes. Now there are 2 versions of the same function - Remove tests. - Move tests to the tests directory. Since the structure of this node is slightly different (adding an atribute) there is a helper inner function that will create the nodes in the structure for the 2 tests that were added. * Unify name of functions in copy_random_pointer.py --- algorithms/arrays/plus_one.py | 4 +- algorithms/linkedlist/__init__.py | 1 + algorithms/linkedlist/copy_random_pointer.py | 72 +++++++++++--------- tests/test_linkedlist.py | 47 ++++++++++++- 4 files changed, 88 insertions(+), 36 deletions(-) diff --git a/algorithms/arrays/plus_one.py b/algorithms/arrays/plus_one.py index f63aafaea..473b6c7d0 100644 --- a/algorithms/arrays/plus_one.py +++ b/algorithms/arrays/plus_one.py @@ -42,7 +42,7 @@ def plus_one_v2(digits): def plus_one_v3(num_arr): for idx in reversed(list(enumerate(num_arr))): - num_arr[idx] = (num_arr[idx] + 1) % 10 - if num_arr[idx]: + num_arr[idx[0]] = (num_arr[idx[0]] + 1) % 10 + if num_arr[idx[0]]: return num_arr return [1] + num_arr diff --git a/algorithms/linkedlist/__init__.py b/algorithms/linkedlist/__init__.py index 21263bfe9..1c9c3b9fc 100644 --- a/algorithms/linkedlist/__init__.py +++ b/algorithms/linkedlist/__init__.py @@ -6,3 +6,4 @@ from .is_cyclic import * from .merge_two_list import * from .is_palindrome import * +from .copy_random_pointer import * diff --git a/algorithms/linkedlist/copy_random_pointer.py b/algorithms/linkedlist/copy_random_pointer.py index 7653d4902..b3ef4628d 100644 --- a/algorithms/linkedlist/copy_random_pointer.py +++ b/algorithms/linkedlist/copy_random_pointer.py @@ -4,35 +4,45 @@ Return a deep copy of the list. """ -# from collections import defaultdict +from collections import defaultdict -# TODO: This requires to be rewritten -- commenting it out for now -# class Solution0: - # @param head, a RandomListNode - # @return a RandomListNode - # def copyRandomList(self, head): - # dic = dict() - # m = n = head - # while m: - # dic[m] = RandomListNode(m.label) - # m = m.next - # while n: - # dic[n].next = dic.get(n.next) - # dic[n].random = dic.get(n.random) - # n = n.next - # return dic.get(head) -# -# -# class Solution1: # O(n) -# @param head, a RandomListNode -# @return a RandomListNode - # def copyRandomList(self, head): - # copy = defaultdict(lambda: RandomListNode(0)) - # copy[None] = None - # node = head - # while node: - # copy[node].label = node.label - # copy[node].next = copy[node.next] - # copy[node].random = copy[node.random] - # node = node.next - # return copy[head] + +class RandomListNode(object): + def __init__(self, label): + self.label = label + self.next = None + self.random = None + + +def copy_random_pointer_v1(head): + """ + :type head: RandomListNode + :rtype: RandomListNode + """ + dic = dict() + m = n = head + while m: + dic[m] = RandomListNode(m.label) + m = m.next + while n: + dic[n].next = dic.get(n.next) + dic[n].random = dic.get(n.random) + n = n.next + return dic.get(head) + + +# O(n) +def copy_random_pointer_v2(head): + """ + :type head: RandomListNode + :rtype: RandomListNode + """ + copy = defaultdict(lambda: RandomListNode(0)) + copy[None] = None + node = head + while node: + copy[node].label = node.label + copy[node].next = copy[node.next] + copy[node].random = copy[node.random] + node = node.next + return copy[head] diff --git a/tests/test_linkedlist.py b/tests/test_linkedlist.py index 435ac7261..6b7f1f4fa 100644 --- a/tests/test_linkedlist.py +++ b/tests/test_linkedlist.py @@ -1,3 +1,5 @@ +import unittest + from algorithms.linkedlist import ( reverse_list, reverse_list_recursive, is_sorted, @@ -6,16 +8,17 @@ rotate_right, is_cyclic, merge_two_list, merge_two_list_recur, - is_palindrome, is_palindrome_stack, is_palindrome_dict + is_palindrome, is_palindrome_stack, is_palindrome_dict, + RandomListNode, copy_random_pointer_v1, copy_random_pointer_v2 ) -import unittest class Node(object): def __init__(self, x): self.val = x self.next = None + # Convert from linked list Node to list for testing def convert(head): ret = [] @@ -26,6 +29,7 @@ def convert(head): current = current.next return ret + class TestSuite(unittest.TestCase): def setUp(self): # list test for palindrome @@ -69,7 +73,6 @@ def test_is_sorted(self): self.assertFalse(is_sorted(head)) def test_remove_range(self): - # Test case: middle case. head = Node(0) head.next = Node(1) @@ -163,12 +166,50 @@ def test_merge_two_list(self): def test_is_palindrome(self): self.assertTrue(is_palindrome(self.l)) self.assertFalse(is_palindrome(self.l1)) + def test_is_palindrome_stack(self): self.assertTrue(is_palindrome_stack(self.l)) self.assertFalse(is_palindrome_stack(self.l1)) + def test_is_palindrome_dict(self): self.assertTrue(is_palindrome_dict(self.l)) self.assertFalse(is_palindrome_dict(self.l1)) + def test_solution_0(self): + self._init_random_list_nodes() + result = copy_random_pointer_v1(self.random_list_node1) + self._assert_is_a_copy(result) + + def test_solution_1(self): + self._init_random_list_nodes() + result = copy_random_pointer_v2(self.random_list_node1) + self._assert_is_a_copy(result) + + def _assert_is_a_copy(self, result): + self.assertEqual(5, result.next.next.next.next.label) + self.assertEqual(4, result.next.next.next.label) + self.assertEqual(3, result.next.next.label) + self.assertEqual(2, result.next.label) + self.assertEqual(1, result.label) + self.assertEqual(3, result.next.next.next.next.random.label) + self.assertIsNone(result.next.next.next.random) + self.assertEqual(2, result.next.next.random.label) + self.assertEqual(5, result.next.random.label) + self.assertEqual(4, result.random.label) + + def _init_random_list_nodes(self): + self.random_list_node1 = RandomListNode(1) + random_list_node2 = RandomListNode(2) + random_list_node3 = RandomListNode(3) + random_list_node4 = RandomListNode(4) + random_list_node5 = RandomListNode(5) + + self.random_list_node1.next, self.random_list_node1.random = random_list_node2, random_list_node4 + random_list_node2.next, random_list_node2.random = random_list_node3, random_list_node5 + random_list_node3.next, random_list_node3.random = random_list_node4, random_list_node2 + random_list_node4.next = random_list_node5 + random_list_node5.random = random_list_node3 + + if __name__ == "__main__": unittest.main() From 996de2744b87f232198b43e03069e21d25c00672 Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Fri, 19 Oct 2018 15:54:18 -0700 Subject: [PATCH 126/302] Add edit distance DP problem (#407) * Add edit distance dp problem * Add tests for dp algorithms * Update edit distance * Add __init__ file for dp --- algorithms/dp/__init__.py | 1 + algorithms/dp/edit_distance.py | 54 ++++++++++++++++++++++++++++++++++ tests/test_dp.py | 16 ++++++++++ 3 files changed, 71 insertions(+) create mode 100644 algorithms/dp/__init__.py create mode 100644 algorithms/dp/edit_distance.py create mode 100644 tests/test_dp.py diff --git a/algorithms/dp/__init__.py b/algorithms/dp/__init__.py new file mode 100644 index 000000000..174f524bf --- /dev/null +++ b/algorithms/dp/__init__.py @@ -0,0 +1 @@ +from .edit_distance import * diff --git a/algorithms/dp/edit_distance.py b/algorithms/dp/edit_distance.py new file mode 100644 index 000000000..ecf6beb06 --- /dev/null +++ b/algorithms/dp/edit_distance.py @@ -0,0 +1,54 @@ +"""The edit distance between two words is the minimum number of letter insertions, +letter deletions, and letter substitutions required to transform one word into another. + +For example, the edit distance between FOOD and MONEY is at most four: + +FOOD -> MOOD -> MOND -> MONED -> MONEY + +Given two words A and B, find the minimum number of operations required to transform one string into the other. +In other words, find the edit distance between A and B. + +Thought process: + +Let edit(i, j) denote the edit distance between the prefixes A[1..i] and B[1..j]. + +Then, the function satifies the following recurrence: + +edit(i, j) = i if j = 0 + j if i = 0 + min(edit(i-1, j) + 1, + edit(i, j-1), + 1, + edit(i-1, j-1) + cost) otherwise + +There are two base cases, both of which occur when one string is empty and the other is not. +1. To convert an empty string A into a string B of length n, perform n insertions. +2. To convert a string A of length m into an empty string B, perform m deletions. + +Here, the cost is 1 if a substitution is required, +or 0 if both chars in words A and B are the same at indexes i and j, respectively. + +To find the edit distance between two words A and B, +we need to find edit(m, n), where m is the length of A and n is the length of B. +""" + + +def edit_distance(A, B): + # Time: O(m*n) + # Space: O(m*n) + + m, n = len(A) + 1, len(B) + 1 + + edit = [[0 for _ in range(n)] for _ in range(m)] + + for i in range(1, m): + edit[i][0] = i + + for j in range(1, n): + edit[0][j] = j + + for i in range(1, m): + for j in range(1, n): + cost = 0 if A[i - 1] == B[j - 1] else 1 + edit[i][j] = min(edit[i - 1][j] + 1, edit[i][j - 1] + 1, edit[i - 1][j - 1] + cost) + + return edit[-1][-1] # this is the same as edit[m][n] diff --git a/tests/test_dp.py b/tests/test_dp.py new file mode 100644 index 000000000..bbec085e2 --- /dev/null +++ b/tests/test_dp.py @@ -0,0 +1,16 @@ +from algorithms.dp import ( + edit_distance +) + + +import unittest + + +class TestEditDistance(unittest.TestCase): + def test_edit_distance(self): + self.assertEqual(edit_distance('food', 'money'), 4) + self.assertEqual(edit_distance('horse', 'ros'), 3) + + +if __name__ == '__main__': + unittest.main() From 81d0e4d81ec55a0c9f5d5f9f7dcefe27e4f9db53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9ssica=20Paz?= Date: Tue, 30 Oct 2018 04:43:04 -0300 Subject: [PATCH 127/302] Add hailstone algorithm (#434) * Add hailstone algorithm in maths * Add hailstone in README file * Change type terms to int * Add hailstone test --- README.md | 1 + algorithms/maths/hailstone.py | 13 +++++++++++++ tests/test_maths.py | 15 ++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 algorithms/maths/hailstone.py diff --git a/README.md b/README.md index aecd53b6d..4443884e4 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,7 @@ If you want to uninstall algorithms, it is as simple as: - [rsa](algorithms/maths/rsa.py) - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - [summing_digits](algorithms/maths/summing_digits.py) + - [hailstone](algorithms/maths/hailstone.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - [bomb_enemy](algorithms/matrix/bomb_enemy.py) diff --git a/algorithms/maths/hailstone.py b/algorithms/maths/hailstone.py new file mode 100644 index 000000000..22321232b --- /dev/null +++ b/algorithms/maths/hailstone.py @@ -0,0 +1,13 @@ +def hailstone(n): + """Return the 'hailstone sequence' from n to 1 + n: The starting point of the hailstone sequence + """ + + sequence = [n] + while n > 1: + if n%2 != 0: + n = 3*n + 1 + else: + n = int(n/2) + sequence.append(n) + return sequence \ No newline at end of file diff --git a/tests/test_maths.py b/tests/test_maths.py index 0777f9ab3..dd1d0e137 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -14,7 +14,8 @@ pythagoras, is_prime, encrypt, decrypt, - combination, combination_memo + combination, combination_memo, + hailstone, ) import unittest @@ -288,5 +289,17 @@ def test_factorial_recur(self): self.assertRaises(ValueError, factorial_recur, 42, -1) +class TestHailstone(unittest.TestCase): + """[summary] + Test for the file hailstone.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_hailstone(self): + self.assertEqual([8, 4, 2, 1], hailstone.hailstone(8)) + self.assertEqual([10, 5, 16, 8, 4, 2, 1], hailstone.hailstone(10)) + + if __name__ == "__main__": unittest.main() From 7a859d2cf46b4222ac30153bb245b26de53af352 Mon Sep 17 00:00:00 2001 From: Semal Patel Date: Mon, 10 Dec 2018 18:18:12 -0800 Subject: [PATCH 128/302] fix function definition (#461) --- algorithms/matrix/rotate_image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py index 0a6fb50b8..21f1c74ee 100644 --- a/algorithms/matrix/rotate_image.py +++ b/algorithms/matrix/rotate_image.py @@ -14,7 +14,7 @@ # 4 5 6 => 4 5 6 => 8 5 2 # 7 8 9 1 2 3 9 6 3 -def rotate(mat:"List[List[int]]"): +def rotate(mat): if not mat: return mat mat.reverse() From 1cfe245af9587f5a44154d6240a86c119735ff98 Mon Sep 17 00:00:00 2001 From: Semal Patel Date: Mon, 10 Dec 2018 18:19:00 -0800 Subject: [PATCH 129/302] edit swap one liner (#458) --- algorithms/heap/binary_heap.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/algorithms/heap/binary_heap.py b/algorithms/heap/binary_heap.py index 5119a0309..629be434a 100644 --- a/algorithms/heap/binary_heap.py +++ b/algorithms/heap/binary_heap.py @@ -59,9 +59,7 @@ def perc_up(self, i): while i // 2 > 0: if self.heap[i] < self.heap[i // 2]: # Swap value of child with value of its parent - tmp = self.heap[i] - self.heap[i] = self.heap[i // 2] - self.heap[i // 2] = tmp + self.heap[i], self.heap[i//2] = self.heap[i//2], self.heap[i] i = i // 2 """ @@ -95,9 +93,7 @@ def perc_down(self, i): min_child = self.min_child(i) if self.heap[min_child] < self.heap[i]: # Swap min child with parent - tmp = self.heap[min_child] - self.heap[min_child] = self.heap[i] - self.heap[i] = tmp + self.heap[min_child], self.heap[i] = self.heap[i], self.heap[min_child] i = min_child """ Remove Min method removes the minimum element and swap it with the last From 6354b689e3b44275451041d13f323394081a94a1 Mon Sep 17 00:00:00 2001 From: ssivart Date: Thu, 13 Dec 2018 15:31:29 +0800 Subject: [PATCH 130/302] Fix invoking function name --- algorithms/graph/minimum_spanning_tree.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/algorithms/graph/minimum_spanning_tree.py b/algorithms/graph/minimum_spanning_tree.py index 2a877f985..dcc6898b6 100644 --- a/algorithms/graph/minimum_spanning_tree.py +++ b/algorithms/graph/minimum_spanning_tree.py @@ -28,8 +28,8 @@ def merge_set(self, a, b): # Get the set of nodes at position and # If and are the roots, this will be constant O(1) - a = self.findSet(a) - b = self.findSet(b) + a = self.find_set(a) + b = self.find_set(b) # Join the shortest node to the longest, minimizing tree size (faster find) if self.size[a] < self.size[b]: @@ -73,8 +73,8 @@ def kruskal(n, edges, ds): mst = [] # List of edges taken, minimum spanning tree for edge in edges: - set_u = ds.findSet(edge.u) # Set of the node - set_v = ds.findSet(edge.v) # Set of the node + set_u = ds.find_set(edge.u) # Set of the node + set_v = ds.find_set(edge.v) # Set of the node if set_u != set_v: ds.merge_set(set_u, set_v) mst.append(edge) @@ -127,4 +127,4 @@ def kruskal(n, edges, ds): edges[i] = Edge(u, v, weight) # After finish input and graph creation, use Kruskal algorithm for MST: - print("MST weights sum:", kruskal(n, edges, ds)) \ No newline at end of file + print("MST weights sum:", kruskal(n, edges, ds)) From 139aae6c23afaf223161e12d7b666d7332239e06 Mon Sep 17 00:00:00 2001 From: Semal Patel Date: Wed, 19 Dec 2018 16:41:39 -0800 Subject: [PATCH 131/302] fix calculator infinite loop (#466) --- algorithms/calculator/math_parser.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/algorithms/calculator/math_parser.py b/algorithms/calculator/math_parser.py index a1d0e0ba5..3cbe1cb56 100644 --- a/algorithms/calculator/math_parser.py +++ b/algorithms/calculator/math_parser.py @@ -93,7 +93,7 @@ def parse(expression): result.append(i) else: raise Exception("invalid syntax " + i) - + if len(current) > 0: result.append(current) return result @@ -133,15 +133,17 @@ def main(): simple user-interface """ print("\t\tCalculator\n\n") - user_input = input("expression or exit: ") - while user_input != "exit": + while True: + user_input = input("expression or exit: ") + if user_input == "exit": + break try: print("The result is {0}".format(evaluate(user_input))) except Exception: print("invalid syntax!") user_input = input("expression or exit: ") print("program end") - + if __name__ == "__main__": main() From 2a664a8268b130c5489fce955e31af8fc77224c4 Mon Sep 17 00:00:00 2001 From: Milton Olaf P Date: Tue, 15 Jan 2019 08:09:24 -0600 Subject: [PATCH 132/302] Add spanish README and CONTRIBUTING (#426) * add spanish readme link * fix EN and FR readme link * add spanish version * add spanish link * add spanish version --- CONTRIBUTING_ES.md | 62 ++++++++ README.md | 2 +- README_CN.md | 2 +- README_ES.md | 376 +++++++++++++++++++++++++++++++++++++++++++++ README_FR.md | 2 +- README_GE.md | 2 +- README_JP.md | 2 +- README_KR.md | 2 +- README_PTBR.md | 2 +- 9 files changed, 445 insertions(+), 7 deletions(-) create mode 100644 CONTRIBUTING_ES.md create mode 100644 README_ES.md diff --git a/CONTRIBUTING_ES.md b/CONTRIBUTING_ES.md new file mode 100644 index 000000000..578b1d4b7 --- /dev/null +++ b/CONTRIBUTING_ES.md @@ -0,0 +1,62 @@ +# Contribuyendo + +Nos encantan los pull requests de todos. Al contribuir a este repositorio, usted acepta cumplir con el [Código de Conducta](CODE_OF_CONDUCT.md). + +## Comenzando + +* Primero haga un [fork][fork] del repositorio y luego clónelo usando: + + git clone git@github.com:your-username/algorithms.git + +* Después de eso, crea una git branch para tus cambios. Por ejemplo: + * add_XXX Si agregara nuevos algoritmos o estructuras de datos. + * fix_XXX Si arreglará un error en un determinado algoritmo o estructura de datos. + * test_XXX Si escribiste una o más pruebas. + * doc_XXX Si ha editado o añadido a la documentación. + +Usted puede contribuir: +- Implementando nuevos algoritmos en el repositorio. Asegúrese de ponerlo en la sección correcta (ej. [array](array), [dp](dp), etc). Cree una nueva sección para él si no cae en ninguna. Asegúrese de que su implementación funciona. +- Optimizando o mejorando los algoritmos existentes. +- Añadiendo una solución diferente para el problema. +- Encontrando y corrigiendo errores. +- Añadiendo ejemplos para explicar mejor los algoritmos. +- Añadiendo casos de prueba. +- Mejorando la documentación. + +## Pull Requests +Haga push a su fork y [envie un pull request][pr]. + +Revisaremos y sugeriremos algunos cambios, mejoras o alternativas. Algunas cosas que aumentarán la posibilidad de que su pull request sea aceptado: + + +* Todos los algoritmos deben estar escritos en **Python 3**. +(Hay algunos algoritmos todavía con la sintaxis de _Python 2_. Puede comenzar con la conversión de [aquellos][issue120] a _Python 3_.) +* Escribir código limpio y comprensible. +* Comente correctamente el código y explique brevemente qué está haciendo el algoritmo en los [docstrings][docstr]. +* También puede explicar la salida usando un ejemplo mínimo. +* Trate de incluir también un par de casos de prueba para el algoritmo. +* Escriba un [buen mensaje en el commit][commit]. + + +## Issues +Envíe un [nuevo issue][newissue] si hay un algoritmo por agregar, o si se encontró un error en un algoritmo existente. Antes de enviar un nuevo issue, revise lo [issues existentes][issues] para evitar crear duplicados. También, considere resolver problemas actuales o contribuir a la discusión sobre un tema. + +## Colaboradores +Puedes pedir ayuda o aclaraciones a los colaboradores. +[Keon Kim](https://github.com/keon) + +[Rahul Goswami](https://github.com/goswami-rahul) + +[Ankit Agarwal](https://github.com/ankit167) + +[Hai Hoang Dang](https://github.com/danghai) + +[Saad](https://github.com/SaadBenn) + +[fork]: https://help.github.com/articles/fork-a-repo/ +[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings +[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[pr]: https://github.com/keon/algorithms/compare/ +[newissue]: https://github.com/keon/algorithms/issues/new +[issue120]: https://github.com/keon/algorithms/issues/120 +[issues]: https://github.com/keon/algorithms/issues/ diff --git a/README.md b/README.md index 4443884e4..151007782 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) +English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_CN.md b/README_CN.md index ee405457a..aec110ad1 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@

-[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) +[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_ES.md b/README_ES.md new file mode 100644 index 000000000..cd6ee82e7 --- /dev/null +++ b/README_ES.md @@ -0,0 +1,376 @@ +

+ +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | Español + +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) +[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + +Estructuras de datos y algoritmos en Python +========================================= + +Ejemplo de implementaciones mínimas y limpias de estructuras de datos y algoritmos en Python 3. + +## Contribuciones +¡Gracias por su interés en contribuir! Hay muchas maneras de contribuir a este proyecto. [Comienza aquí](CONTRIBUTING_ES.md) + +## Pruebas + +### Usando unittest +Escriba lo siguiente para ejecutar todas las pruebas: + + $ python3 -m unittest discover tests + +Para ejecutar pruebas en específico, puede hacerlo de la siguiente manera (Ej: sort): + + $ python3 -m unittest tests.test_sort + +### Usando pytest +Escriba lo siguiente para ejecutar todas las pruebas: + + $ python3 -m pytest tests + +## Instalación +Si desea utilizar el API algorithms en su código, es tan simple como: + + $ pip3 install algorithms + +Puede probar creando un archivo python: (Ej: use `merge_sort` en `sort`) + +```python3 +from algorithms.sort import merge_sort + +if __name__ == "__main__": + my_list = [1, 8, 3, 5, 6] + my_list = merge_sort(my_list) + print(my_list) +``` + +## Desinstalación +Si desea desinstalar algorithms, es tan simple como: + + $ pip3 uninstall -y algorithms + +## Lista de immplementaciones + +- [arrays](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) + - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros](algorithms/arrays/move_zeros.py) + - [n_sum](algorithms/arrays/n_sum.py) +- [backtrack](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [add_operators](algorithms/backtrack/add_operators.py) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit](algorithms/bit) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_difference](algorithms/bit/find_difference.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) + - [binary_gap](algorithms/bit/binary_gap.py) +- [calculator](algorithms/calculator) + - [math_parser](algorithms/calculator/math_parser.py) +- [dfs](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [dp](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) +- [graph](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) + - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) +- [heap](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) +- [linkedlist](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) + - [word_pattern](algorithms/map/word_pattern.py) + - [is_isomorphic](algorithms/map/is_isomorphic.py) + - [is_anagram](algorithms/map/is_anagram.py) +- [maths](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [combination](algorithms/maths/combination.py) + - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) + - [euler_totient](algorithms/maths/euler_totient.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) +- [matrix](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) +- [queues](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurrence](algorithms/search/first_occurrence.py) + - [last_occurrence](algorithms/search/last_occurrence.py) + - [linear_search](algorithms/search/linear_search.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) + - [next_greatest_letter](algorithms/search/next_greatest_letter.py) +- [set](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) + - [find_keyboard_row](algorithms/set/find_keyboard_row.py) +- [sort](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) + - [bogo_sort](algorithms/sort/bogo_sort.py) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [top_sort](algorithms/sort/top_sort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [strings](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) + - [unique_morse](algorithms/strings/unique_morse.py) + - [judge_circle](algorithms/strings/judge_circle.py) + - [strong_password](algorithms/strings/strong_password.py) + - [caesar_cipher](algorithms/strings/caesar_cipher.py) + - [contain_string](algorithms/strings/contain_string.py) + - [count_binary_substring](algorithms/strings/count_binary_substring.py) + - [repeat_string](algorithms/strings/repeat_string.py) + - [min_distance](algorithms/strings/min_distance.py) + - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) + - [rotate](algorithms/strings/rotate.py) + - [first_unique_char](algorithms/strings/first_unique_char.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) +- [tree](algorithms/tree) + - [bst](algorithms/tree/bst) + - [array_to_bst](algorithms/tree/bst/array_to_bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [unix](algorithms/unix) + - [path](algorithms/unix/path/) + - [join_with_slash](algorithms/unix/path/join_with_slash.py) + - [full_path](algorithms/unix/path/full_path.py) + - [split](algorithms/unix/path/split.py) + - [simplify_path](algorithms/unix/path/simplify_path.py) +- [union-find](algorithms/union-find) + - [count_islands](algorithms/union-find/count_islands.py) +- [machine-learning](algorithms/machine-learning) + - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) + +## Colaboradores +El repositorio es mantenido por + +* [Keon Kim](https://github.com/keon) +* [Rahul Goswami](https://github.com/goswami-rahul) +* [Christian Bender](https://github.com/christianbender) +* [Ankit Agarwal](https://github.com/ankit167) +* [Hai Hoang Dang](https://github.com/danghai) +* [Saad](https://github.com/SaadBenn) + +Y gracias a [todos los colaboradores](https://github.com/keon/algorithms/graphs/contributors) +que ayudaron en la construcción del repositorio. diff --git a/README_FR.md b/README_FR.md index bfe2f905a..aecd40e95 100644 --- a/README_FR.md +++ b/README_FR.md @@ -1,6 +1,6 @@

-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | Français | [Español](README_ES.md) [![Version PyPI](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Contributeurs open source](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_GE.md b/README_GE.md index 782c494c0..e88d5c3f1 100644 --- a/README_GE.md +++ b/README_GE.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) +[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_JP.md b/README_JP.md index b5fff7bc9..98d1eb5fc 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_KR.md b/README_KR.md index cf0912506..e3114f37f 100644 --- a/README_KR.md +++ b/README_KR.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) | [Français](README_FR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) diff --git a/README_PTBR.md b/README_PTBR.md index efe3b1ba0..e0ca1a16a 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -1,6 +1,6 @@

-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português | [Français](README_FR.md) +[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português | [Français](README_FR.md) | [Español](README_ES.md) [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) From 851dcb50202f33d88bf1b2952fee0f3b95dd446b Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Wed, 16 Jan 2019 05:58:46 -0800 Subject: [PATCH 133/302] Add k closest points to origin (#435) * Add k closest points to origin * Update heap init file * Add tests for k closest points to origin * Add k closest points link to README * Update k closest points to origin Co-Authored-By: vinceajcs --- README.md | 1 + algorithms/heap/__init__.py | 2 ++ algorithms/heap/k_closest_points.py | 44 +++++++++++++++++++++++++++++ tests/test_heap.py | 29 +++++++++++++------ 4 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 algorithms/heap/k_closest_points.py diff --git a/README.md b/README.md index 151007782..1d905d01f 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ If you want to uninstall algorithms, it is as simple as: - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) + - [k_closest_points](algorithms/heap/k_closest_points.py) - [linkedlist](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) diff --git a/algorithms/heap/__init__.py b/algorithms/heap/__init__.py index 3731b0ee9..9ea682d09 100644 --- a/algorithms/heap/__init__.py +++ b/algorithms/heap/__init__.py @@ -1,3 +1,5 @@ from .binary_heap import * from .skyline import * from .sliding_window_max import * +from .merge_sorted_k_lists import * +from .k_closest_points import * diff --git a/algorithms/heap/k_closest_points.py b/algorithms/heap/k_closest_points.py new file mode 100644 index 000000000..8e38e05e5 --- /dev/null +++ b/algorithms/heap/k_closest_points.py @@ -0,0 +1,44 @@ +"""Given a list of points, find the k closest to the origin. + +Idea: Maintain a max heap of k elements. +We can iterate through all points. +If a point p has a smaller distance to the origin than the top element of a heap, we add point p to the heap and remove the top element. +After iterating through all points, our heap contains the k closest points to the origin. +""" + + +from heapq import heapify, heappushpop + + +def k_closest(points, k, origin=(0, 0)): + # Time: O(k+(n-k)logk) + # Space: O(k) + """Initialize max heap with first k points. + Python does not support a max heap; thus we can use the default min heap where the keys (distance) are negated. + """ + heap = [(-distance(p, origin), p) for p in points[:k]] + heapify(heap) + + """ + For every point p in points[k:], + check if p is smaller than the root of the max heap; + if it is, add p to heap and remove root. Reheapify. + """ + for p in points[k:]: + d = distance(p, origin) + + heappushpop(heap, (-d, p)) # heappushpop does conditional check + """Same as: + if d < -heap[0][0]: + heappush(heap, (-d,p)) + heappop(heap) + + Note: heappushpop is more efficient than separate push and pop calls. + Each heappushpop call takes O(logk) time. + """ + + return [p for nd, p in heap] # return points in heap + + +def distance(point, origin=(0, 0)): + return (point[0] - origin[0])**2 + (point[1] - origin[1])**2 diff --git a/tests/test_heap.py b/tests/test_heap.py index 0925972dd..91e144da2 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -1,15 +1,18 @@ from algorithms.heap import ( BinaryHeap, get_skyline, - max_sliding_window + max_sliding_window, + k_closest_points ) import unittest + class TestBinaryHeap(unittest.TestCase): """ Test suite for the binary_heap data structures """ + def setUp(self): self.min_heap = BinaryHeap() self.min_heap.insert(4) @@ -24,7 +27,7 @@ def test_insert(self): # After insert: [0, 2, 50, 4, 55, 90, 87, 7] self.min_heap.insert(2) self.assertEqual([0, 2, 50, 4, 55, 90, 87, 7], - self.min_heap.heap) + self.min_heap.heap) self.assertEqual(7, self.min_heap.currentSize) def test_remove_min(self): @@ -32,23 +35,33 @@ def test_remove_min(self): # Before remove_min : [0, 4, 50, 7, 55, 90, 87] # After remove_min: [7, 50, 87, 55, 90] # Test return value - self.assertEqual(4,ret) + self.assertEqual(4, ret) self.assertEqual([0, 7, 50, 87, 55, 90], - self.min_heap.heap) + self.min_heap.heap) self.assertEqual(5, self.min_heap.currentSize) + class TestSuite(unittest.TestCase): def test_get_skyline(self): - buildings = [ [2, 9, 10], [3, 7, 15], [5, 12, 12], \ - [15, 20, 10], [19, 24, 8] ] + buildings = [[2, 9, 10], [3, 7, 15], [5, 12, 12], + [15, 20, 10], [19, 24, 8]] # Expect output - output = [ [2, 10], [3, 15], [7, 12], [12, 0], [15, 10], \ - [20, 8], [24, 0] ] + output = [[2, 10], [3, 15], [7, 12], [12, 0], [15, 10], + [20, 8], [24, 0]] self.assertEqual(output, get_skyline(buildings)) def test_max_sliding_window(self): nums = [1, 3, -1, -3, 5, 3, 6, 7] self.assertEqual([3, 3, 5, 5, 6, 7], max_sliding_window(nums, 3)) + def test_k_closest_points(self): + points = [(1, 0), (2, 3), (5, 2), (1, 1), (2, 8), (10, 2), (-1, 0), (-2, -2)] + self.assertEqual([(-1, 0), (1, 0)], k_closest(points, 2)) + self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest(points, 3)) + self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest(points, 4)) + self.assertEqual([(10, 2), (2, 8), (5, 2), (-2, -2), (2, 3), + (1, 0), (-1, 0), (1, 1)], k_closest(points, 8)) + + if __name__ == "__main__": unittest.main() From c3bfeab12c7163a6e7dce97840fa7b81b4f2bc16 Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Thu, 24 Jan 2019 16:50:28 +0800 Subject: [PATCH 134/302] fix: test_heap (#475) --- tests/test_heap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_heap.py b/tests/test_heap.py index 91e144da2..6814c6196 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -2,7 +2,7 @@ BinaryHeap, get_skyline, max_sliding_window, - k_closest_points + k_closest ) import unittest From d31ec0a453b6f8091996249de10e35d089035637 Mon Sep 17 00:00:00 2001 From: Notheryne <43877088+Notheryne@users.noreply.github.com> Date: Thu, 24 Jan 2019 09:51:46 +0100 Subject: [PATCH 135/302] add atbash, crout, hosoya triangle algorithms (#470) * add atbash, crout, hosoya triangle algorithms * add tests, update readmes --- README.md | 3 ++ README_ES.md | 5 +- README_FR.md | 5 +- README_GE.md | 3 ++ README_JP.md | 3 ++ README_KR.md | 3 ++ README_PTBR.md | 3 ++ algorithms/dp/hosoya_triangle.py | 45 ++++++++++++++++++ .../matrix/crout_matrix_decomposition.py | 47 +++++++++++++++++++ algorithms/strings/__init__.py | 1 + algorithms/strings/atbash_cipher.py | 27 +++++++++++ tests/test_dp.py | 32 ++++++++++++- tests/test_matrix.py | 46 ++++++++++++++++++ tests/test_strings.py | 16 ++++++- 14 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 algorithms/dp/hosoya_triangle.py create mode 100644 algorithms/matrix/crout_matrix_decomposition.py create mode 100644 algorithms/strings/atbash_cipher.py create mode 100644 tests/test_matrix.py diff --git a/README.md b/README.md index 1d905d01f..13f760602 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ If you want to uninstall algorithms, it is as simple as: - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) @@ -216,6 +217,7 @@ If you want to uninstall algorithms, it is as simple as: - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -306,6 +308,7 @@ If you want to uninstall algorithms, it is as simple as: - [rotate](algorithms/strings/rotate.py) - [first_unique_char](algorithms/strings/first_unique_char.py) - [repeat_substring](algorithms/strings/repeat_substring.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree](algorithms/tree) - [bst](algorithms/tree/bst) - [array_to_bst](algorithms/tree/bst/array_to_bst.py) diff --git a/README_ES.md b/README_ES.md index cd6ee82e7..045c332f4 100644 --- a/README_ES.md +++ b/README_ES.md @@ -140,6 +140,7 @@ Si desea desinstalar algorithms, es tan simple como: - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) @@ -214,6 +215,7 @@ Si desea desinstalar algorithms, es tan simple como: - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -303,7 +305,8 @@ Si desea desinstalar algorithms, es tan simple como: - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) - [rotate](algorithms/strings/rotate.py) - [first_unique_char](algorithms/strings/first_unique_char.py) - - [repeat_substring](algorithms/strings/repeat_substring.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree](algorithms/tree) - [bst](algorithms/tree/bst) - [array_to_bst](algorithms/tree/bst/array_to_bst.py) diff --git a/README_FR.md b/README_FR.md index aecd40e95..fc6d41f7a 100644 --- a/README_FR.md +++ b/README_FR.md @@ -139,6 +139,7 @@ Si vous voulez désinstaller le paquet algorithms, il suffit de procéder comme - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) @@ -212,6 +213,7 @@ Si vous voulez désinstaller le paquet algorithms, il suffit de procéder comme - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -301,7 +303,8 @@ Si vous voulez désinstaller le paquet algorithms, il suffit de procéder comme - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) - [rotate](algorithms/strings/rotate.py) - [first_unique_char](algorithms/strings/first_unique_char.py) - - [repeat_substring](algorithms/strings/repeat_substring.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/README_GE.md b/README_GE.md index e88d5c3f1..ab68bdda2 100644 --- a/README_GE.md +++ b/README_GE.md @@ -146,6 +146,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) @@ -215,6 +216,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -291,6 +293,7 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [reverse_words](algorithms/strings/reverse_words.py) - [roman_to_int](algorithms/strings/roman_to_int.py) - [word_squares](algorithms/strings/word_squares.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/README_JP.md b/README_JP.md index 98d1eb5fc..ca31babbb 100644 --- a/README_JP.md +++ b/README_JP.md @@ -140,6 +140,7 @@ if __name__ == "__main__": - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph : グラフ](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) @@ -209,6 +210,7 @@ if __name__ == "__main__": - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues : キュー](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -285,6 +287,7 @@ if __name__ == "__main__": - [reverse_words](algorithms/strings/reverse_words.py) - [roman_to_int](algorithms/strings/roman_to_int.py) - [word_squares](algorithms/strings/word_squares.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree : 木構造](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/README_KR.md b/README_KR.md index e3114f37f..f0f583e4c 100644 --- a/README_KR.md +++ b/README_KR.md @@ -136,6 +136,7 @@ if __name__ == "__main__": - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph : 그래프](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) @@ -205,6 +206,7 @@ if __name__ == "__main__": - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues : 큐](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -279,6 +281,7 @@ if __name__ == "__main__": - [reverse_words](algorithms/strings/reverse_words.py) - [roman_to_int](algorithms/strings/roman_to_int.py) - [word_squares](algorithms/strings/word_squares.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree : 트리](algorithms/tree) - [bst : 이진 탐색 트리](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/README_PTBR.md b/README_PTBR.md index e0ca1a16a..a93f45d03 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -138,6 +138,7 @@ Se você deseja desinstalar os algoritmos, é tão simples quanto: - [rod_cut](algorithms/dp/rod_cut.py) - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) @@ -207,6 +208,7 @@ Se você deseja desinstalar os algoritmos, é tão simples quanto: - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) @@ -289,6 +291,7 @@ Se você deseja desinstalar os algoritmos, é tão simples quanto: - [caesar_cipher](algorithms/strings/caesar_cipher.py) - [contain_string](algorithms/strings/contain_string.py) - [count_binary_substring](algorithms/strings/count_binary_substring.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [tree](algorithms/tree) - [bst](algorithms/tree/tree/bst) - [array2bst](algorithms/tree/bst/array2bst.py) diff --git a/algorithms/dp/hosoya_triangle.py b/algorithms/dp/hosoya_triangle.py new file mode 100644 index 000000000..9bf9437ec --- /dev/null +++ b/algorithms/dp/hosoya_triangle.py @@ -0,0 +1,45 @@ +""" +Hosoya triangle (originally Fibonacci triangle) is a triangular arrangement +of numbers, where if you take any number it is the sum of 2 numbers above. +First line is always 1, and second line is always {1 1}. + +This printHosoya function takes argument n which is the height of the triangle +(number of lines). + +For example: +printHosoya( 6 ) would return: +1 +1 1 +2 1 2 +3 2 2 3 +5 3 4 3 5 +8 5 6 6 5 8 + +The complexity is O(n^3). + +""" + + +def hosoya(n, m): + if ((n == 0 and m == 0) or (n == 1 and m == 0) or + (n == 1 and m == 1) or (n == 2 and m == 1)): + return 1 + if n > m: + return hosoya(n - 1, m) + hosoya(n - 2, m) + elif m == n: + return hosoya(n - 1, m - 1) + hosoya(n - 2, m - 2) + else: + return 0 + +def print_hosoya(n): + for i in range(n): + for j in range(i + 1): + print(hosoya(i, j) , end = " ") + print ("\n", end = "") + +def hosoya_testing(n): + x = [] + for i in range(n): + for j in range(i + 1): + x.append(hosoya(i, j)) + return x diff --git a/algorithms/matrix/crout_matrix_decomposition.py b/algorithms/matrix/crout_matrix_decomposition.py new file mode 100644 index 000000000..46929b517 --- /dev/null +++ b/algorithms/matrix/crout_matrix_decomposition.py @@ -0,0 +1,47 @@ +""" +Crout matrix decomposition is used to find two matrices that, when multiplied +give our input matrix, so L * U = A. +L stands for lower and L has non-zero elements only on diagonal and below. +U stands for upper and U has non-zero elements only on diagonal and above. + +This can for example be used to solve systems of linear equations. +The last if is used if to avoid dividing by zero. + +Example: +We input the A matrix: +[[1,2,3], +[3,4,5], +[6,7,8]] + +We get: +L = [1.0, 0.0, 0.0] + [3.0, -2.0, 0.0] + [6.0, -5.0, 0.0] +U = [1.0, 2.0, 3.0] + [0.0, 1.0, 2.0] + [0.0, 0.0, 1.0] + +We can check that L * U = A. + +I think the complexity should be O(n^3). +""" + +def crout_matrix_decomposition(A): + n = len(A) + L = [[0.0] * n for i in range(n)] + U = [[0.0] * n for i in range(n)] + for j in range(n): + U[j][j] = 1.0 + for i in range(j, n): + alpha = float(A[i][j]) + for k in range(j): + alpha -= L[i][k]*U[k][j] + L[i][j] = float(alpha) + for i in range(j+1, n): + tempU = float(A[j][i]) + for k in range(j): + tempU -= float(L[j][k]*U[k][i]) + if int(L[j][j]) == 0: + L[j][j] = float(0.1**40) + U[j][i] = float(tempU/L[j][j]) + return (L,U) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 98306f61d..9110a0f2c 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -34,3 +34,4 @@ from .rotate import * from .first_unique_char import * from .repeat_substring import * +from .atbash_cipher import * diff --git a/algorithms/strings/atbash_cipher.py b/algorithms/strings/atbash_cipher.py new file mode 100644 index 000000000..59bf777db --- /dev/null +++ b/algorithms/strings/atbash_cipher.py @@ -0,0 +1,27 @@ +""" +Atbash cipher is mapping the alphabet to it's reverse. +So if we take "a" as it is the first letter, we change it to the last - z. + +Example: +Attack at dawn --> Zggzxp zg wzdm + +Complexity: O(n) +""" + +def atbash(s): + translated = "" + for i in range(len(s)): + n = ord(s[i]) + + if s[i].isalpha(): + + if s[i].isupper(): + x = n - ord('A') + translated += chr(ord('Z') - x) + + if s[i].islower(): + x = n - ord('a') + translated += chr(ord('z') - x) + else: + translated += s[i] + return translated \ No newline at end of file diff --git a/tests/test_dp.py b/tests/test_dp.py index bbec085e2..e273f7479 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -1,5 +1,6 @@ from algorithms.dp import ( - edit_distance + edit_distance, + hosoya_triangle ) @@ -11,6 +12,35 @@ def test_edit_distance(self): self.assertEqual(edit_distance('food', 'money'), 4) self.assertEqual(edit_distance('horse', 'ros'), 3) +class TestHosoyaTriangle(unittest.TestCase): + """[summary] + Test for the file hosoya_triangle + + Arguments: + unittest {[type]} -- [description] + """ + + def test_hosoya(self): + self.assertEqual([1], hosoya_testing(1)) + self.assertEqual([1, + 1, 1, + 2, 1, 2, + 3, 2, 2, 3, + 5, 3, 4, 3, 5, + 8, 5, 6, 6, 5, 8], + hosoya_testing(6)) + self.assertEqual([1, + 1, 1, + 2, 1, 2, + 3, 2, 2, 3, + 5, 3, 4, 3, 5, + 8, 5, 6, 6, 5, 8, + 13, 8, 10, 9, 10, 8, 13, + 21, 13, 16, 15, 15, 16, 13, 21, + 34, 21, 26, 24, 25, 24, 26, 21, 34, + 55, 34, 42, 39, 40, 40, 39, 42, 34, 55], + hosoya_testing(10)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_matrix.py b/tests/test_matrix.py new file mode 100644 index 000000000..7c9aa0b3f --- /dev/null +++ b/tests/test_matrix.py @@ -0,0 +1,46 @@ +from algorithms.matrix import ( + crout_matrix_decomposition + ) + + +import unittest + + +class TestCroutMatrixDecomposition(unittest.TestCase): + """[summary] + Test for the file crout_matrix_decomposition.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_crout_matrix_decomposition(self): + self.assertEqual(([[9.0, 0.0], [7.0, 0.0]], + [[1.0, 1.0], [0.0, 1.0]]), + crout_matrix_decomposition([[9,9], [7,7]])) + + self.assertEqual(([[1.0, 0.0, 0.0], + [3.0, -2.0, 0.0], + [6.0, -5.0, 0.0]], + [[1.0, 2.0, 3.0], + [0.0, 1.0, 2.0], + [0.0, 0.0, 1.0]]), + crout_matrix_decomposition([[1,2,3],[3,4,5],[6,7,8]])) + + self.assertEqual(([[2.0, 0, 0, 0], + [4.0, -1.0, 0, 0], + [6.0, -2.0, 2.0, 0], + [8.0, -3.0, 3.0, 0.0]], + [[1.0, 0.5, 1.5, 0.5], + [0, 1.0, 2.0, 1.0], + [0, 0, 1.0, 0.0], + [0, 0, 0, 1.0]]), + crout_matrix_decomposition([[2,1,3,1], + [4,1,4,1], + [6,1,7,1], + [8,1,9,1]])) + + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_strings.py b/tests/test_strings.py index 4474b75b2..66f91919d 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -36,7 +36,8 @@ longest_common_prefix_v1, longest_common_prefix_v2, longest_common_prefix_v3, rotate, first_unique_char, - repeat_substring + repeat_substring, + atbash_cipher ) import unittest @@ -517,6 +518,19 @@ def test_repeat_substring(self): self.assertFalse(repeat_substring("aba")) self.assertTrue(repeat_substring("abcabcabcabc")) +class TestAtbashCipher(unittest.TestCase): + """[summary] + Test for the file atbash_cipher.py + Arguments: + unittest {[type]} -- [description] + """ + + def test_atbash_cipher(self): + self.assertEqual("zyxwvutsrqponml", atbash("abcdefghijklmno")) + self.assertEqual("KbgslM", atbash("PythoN")) + self.assertEqual("AttaCK at DawN", atbash("ZggzXP zg WzdM")) + self.assertEqual("ZggzXP zg WzdM", atbash("AttaCK at DawN")) + if __name__ == "__main__": unittest.main() From f5ce7be45b651ee96834d2fe7fabfbb92e2da355 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 16 Feb 2019 00:27:31 +0800 Subject: [PATCH 136/302] Fix some bug (#366) * Fix bug: explicity compare with None. * Unify node class * Hide slower code. * Update * Only test when file is main * Remove unnecessary code. * Rename and hide implementations. * Fix flake8 * Fix error. * Fix error. * Create __init__.py * Fix error. --- algorithms/matrix/__init__.py | 1 + algorithms/tree/bin_tree_to_list.py | 20 ++------- algorithms/tree/binary_tree_paths.py | 5 ++- algorithms/tree/deepest_left.py | 33 ++++++++------- algorithms/tree/invert_tree.py | 2 +- algorithms/tree/is_balanced.py | 41 ++++++++++--------- algorithms/tree/is_subtree.py | 6 +-- algorithms/tree/is_symmetric.py | 12 +++--- algorithms/tree/longest_consecutive.py | 4 +- algorithms/tree/lowest_common_ancestor.py | 4 +- algorithms/tree/max_height.py | 50 +++++++++++------------ algorithms/tree/max_path_sum.py | 4 +- algorithms/tree/min_height.py | 44 ++++++++++---------- algorithms/tree/path_sum.py | 20 ++++----- algorithms/tree/path_sum2.py | 25 ++++++------ algorithms/tree/pretty_print.py | 1 + algorithms/tree/same_tree.py | 4 +- algorithms/tree/tree.py | 3 -- tests/test_dp.py | 6 +-- tests/test_matrix.py | 14 +++---- tests/test_strings.py | 2 +- 21 files changed, 143 insertions(+), 158 deletions(-) create mode 100644 algorithms/matrix/__init__.py diff --git a/algorithms/matrix/__init__.py b/algorithms/matrix/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/algorithms/matrix/__init__.py @@ -0,0 +1 @@ + diff --git a/algorithms/tree/bin_tree_to_list.py b/algorithms/tree/bin_tree_to_list.py index d23834b12..566ef7568 100644 --- a/algorithms/tree/bin_tree_to_list.py +++ b/algorithms/tree/bin_tree_to_list.py @@ -1,8 +1,5 @@ -class Node(): - def __init__(self, val = 0): - self.val = val - self.left = None - self.right = None +from tree.tree import TreeNode + def bin_tree_to_list(root): """ @@ -15,6 +12,7 @@ def bin_tree_to_list(root): root = root.left return root + def bin_tree_to_list_util(root): if not root: return root @@ -32,18 +30,8 @@ def bin_tree_to_list_util(root): root.right = right return root + def print_tree(root): while root: print(root.val) root = root.right - -tree = Node(10) -tree.left = Node(12) -tree.right = Node(15) -tree.left.left = Node(25) -tree.left.left.right = Node(100) -tree.left.right = Node(30) -tree.right.left = Node(36) - -head = bin_tree_to_list(tree) -print_tree(head) diff --git a/algorithms/tree/binary_tree_paths.py b/algorithms/tree/binary_tree_paths.py index 3de72f710..218064b97 100644 --- a/algorithms/tree/binary_tree_paths.py +++ b/algorithms/tree/binary_tree_paths.py @@ -1,12 +1,13 @@ def binary_tree_paths(root): res = [] - if not root: + if root is None: return res dfs(res, root, str(root.val)) return res + def dfs(res, root, cur): - if not root.left and not root.right: + if root.left is None and root.right is None: res.append(cur) if root.left: dfs(res, root.left, cur+'->'+str(root.left.val)) diff --git a/algorithms/tree/deepest_left.py b/algorithms/tree/deepest_left.py index 1448bc979..6d3a1c262 100644 --- a/algorithms/tree/deepest_left.py +++ b/algorithms/tree/deepest_left.py @@ -12,18 +12,15 @@ # 7 # should return 4. +from tree.tree import TreeNode -class Node: - def __init__(self, val = None): - self.left = None - self.right = None - self.val = val class DeepestLeft: def __init__(self): self.depth = 0 self.Node = None + def find_deepest_left(root, is_left, depth, res): if not root: return @@ -33,15 +30,17 @@ def find_deepest_left(root, is_left, depth, res): find_deepest_left(root.left, True, depth + 1, res) find_deepest_left(root.right, False, depth + 1, res) -root = Node(1) -root.left = Node(2) -root.right = Node(3) -root.left.left = Node(4) -root.left.right = Node(5) -root.right.right = Node(6) -root.right.right.right = Node(7) - -res = DeepestLeft() -find_deepest_left(root, True, 1, res) -if res.Node: - print(res.Node.val) + +if __name__ == '__main__': + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.left.right = TreeNode(5) + root.right.right = TreeNode(6) + root.right.right.right = TreeNode(7) + + res = DeepestLeft() + find_deepest_left(root, True, 1, res) + if res.Node: + print(res.Node.val) diff --git a/algorithms/tree/invert_tree.py b/algorithms/tree/invert_tree.py index 2d70c4f8e..9a6d58eee 100644 --- a/algorithms/tree/invert_tree.py +++ b/algorithms/tree/invert_tree.py @@ -1,7 +1,7 @@ # invert a binary tree def reverse(root): - if not root: + if root is None: return root.left, root.right = root.right, root.left if root.left: diff --git a/algorithms/tree/is_balanced.py b/algorithms/tree/is_balanced.py index 7d3297d32..004daaa37 100644 --- a/algorithms/tree/is_balanced.py +++ b/algorithms/tree/is_balanced.py @@ -1,33 +1,36 @@ - def is_balanced(root): + return __is_balanced_recursive(root) + + +def __is_balanced_recursive(root): """ O(N) solution """ - return -1 != get_depth(root) + return -1 != __get_depth(root) + -def get_depth(root): +def __get_depth(root): """ return 0 if unbalanced else depth + 1 """ - if not root: + if root is None: return 0 - left = get_depth(root.left) - right = get_depth(root.right) - if abs(left-right) > 1 or left == -1 or right == -1: + left = __get_depth(root.left) + right = __get_depth(root.right) + if abs(left-right) > 1 or -1 in [left, right]: return -1 return 1 + max(left, right) -################################ -def is_balanced(root): - """ - O(N^2) solution - """ - left = max_height(root.left) - right = max_height(root.right) - return abs(left-right) <= 1 and is_balanced(root.left) and is_balanced(root.right) +# def is_balanced(root): +# """ +# O(N^2) solution +# """ +# left = max_height(root.left) +# right = max_height(root.right) +# return abs(left-right) <= 1 and is_balanced(root.left) and is_balanced(root.right) -def max_height(root): - if not root: - return 0 - return max(max_height(root.left), max_height(root.right)) + 1 +# def max_height(root): +# if root is None: +# return 0 +# return max(max_height(root.left), max_height(root.right)) + 1 diff --git a/algorithms/tree/is_subtree.py b/algorithms/tree/is_subtree.py index 844b0d5f7..3e267f76e 100644 --- a/algorithms/tree/is_subtree.py +++ b/algorithms/tree/is_subtree.py @@ -64,10 +64,8 @@ def is_subtree(big, small): def comp(p, q): - if not p and not q: + if p is None and q is None: return True - if p and q: + if p is not None and q is not None: return p.val == q.val and comp(p.left,q.left) and comp(p.right, q.right) return False - - diff --git a/algorithms/tree/is_symmetric.py b/algorithms/tree/is_symmetric.py index 0fd56b9aa..19bcd4526 100644 --- a/algorithms/tree/is_symmetric.py +++ b/algorithms/tree/is_symmetric.py @@ -21,28 +21,28 @@ # TC: O(b) SC: O(log n) def is_symmetric(root): - if not root: + if root is None: return True return helper(root.left, root.right) def helper(p, q): - if not p and not q: + if p is None and q is None: return True - if not p or not q or q.val != p.val: + if p is not None or q is not None or q.val != p.val: return False return helper(p.left, q.right) and helper(p.right, q.left) def is_symmetric_iterative(root): - if not root: + if root is None: return True stack = [[root.left, root.right]] while stack: left, right = stack.pop() # popleft - if not left and not right: + if left is None and right is None: continue - if not left or not right: + if left is None or right is None: return False if left.val == right.val: stack.append([left.left, right.right]) diff --git a/algorithms/tree/longest_consecutive.py b/algorithms/tree/longest_consecutive.py index 4fd809a1c..84118010c 100644 --- a/algorithms/tree/longest_consecutive.py +++ b/algorithms/tree/longest_consecutive.py @@ -30,7 +30,7 @@ def longest_consecutive(root): :type root: TreeNode :rtype: int """ - if not root: + if root is None: return 0 max_len = 0 dfs(root, 0, root.val, max_len) @@ -38,7 +38,7 @@ def longest_consecutive(root): def dfs(root, cur, target, max_len): - if not root: + if root is None: return if root.val == target: cur += 1 diff --git a/algorithms/tree/lowest_common_ancestor.py b/algorithms/tree/lowest_common_ancestor.py index 5c4016aed..d0f33ccd1 100644 --- a/algorithms/tree/lowest_common_ancestor.py +++ b/algorithms/tree/lowest_common_ancestor.py @@ -28,10 +28,10 @@ def lca(root, p, q): :type q: TreeNode :rtype: TreeNode """ - if not root or root is p or root is q: + if root is None or root is p or root is q: return root left = lca(root.left, p, q) right = lca(root.right, p, q) - if left and right: + if left is not None and right is not None: return root return left if left else right diff --git a/algorithms/tree/max_height.py b/algorithms/tree/max_height.py index a88a3fff2..ee9c80cde 100644 --- a/algorithms/tree/max_height.py +++ b/algorithms/tree/max_height.py @@ -5,21 +5,18 @@ longest path from the root node down to the farthest leaf node. """ - -class Node(): - def __init__(self, val = 0): - self.val = val - self.left = None - self.right = None - # def max_height(root): - # if not root: - # return 0 - # return max(maxDepth(root.left), maxDepth(root.right)) + 1 +# if not root: +# return 0 +# return max(maxDepth(root.left), maxDepth(root.right)) + 1 # iterative + +from tree.tree import TreeNode + + def max_height(root): - if not root: + if root is None: return 0 height = 0 queue = [root] @@ -28,27 +25,30 @@ def max_height(root): level = [] while queue: node = queue.pop(0) - if node.left: + if node.left is not None: level.append(node.left) - if node.right: + if node.right is not None: level.append(node.right) queue = level return height + def print_tree(root): - if root: + if root is not None: print(root.val) print_tree(root.left) print_tree(root.right) -tree = Node(10) -tree.left = Node(12) -tree.right = Node(15) -tree.left.left = Node(25) -tree.left.left.right = Node(100) -tree.left.right = Node(30) -tree.right.left = Node(36) - -height = max_height(tree) -print_tree(tree) -print("height:", height) + +if __name__ == '__main__': + tree = TreeNode(10) + tree.left = TreeNode(12) + tree.right = TreeNode(15) + tree.left.left = TreeNode(25) + tree.left.left.right = TreeNode(100) + tree.left.right = TreeNode(30) + tree.right.left = TreeNode(36) + + height = max_height(tree) + print_tree(tree) + print("height:", height) diff --git a/algorithms/tree/max_path_sum.py b/algorithms/tree/max_path_sum.py index 10559b52a..7f630fe6b 100644 --- a/algorithms/tree/max_path_sum.py +++ b/algorithms/tree/max_path_sum.py @@ -1,5 +1,3 @@ - - def max_path_sum(root): maximum = float("-inf") helper(root, maximum) @@ -7,7 +5,7 @@ def max_path_sum(root): def helper(root, maximum): - if not root: + if root is None: return 0 left = helper(root.left, maximum) right = helper(root.right, maximum) diff --git a/algorithms/tree/min_height.py b/algorithms/tree/min_height.py index a3923d43e..a33517dec 100644 --- a/algorithms/tree/min_height.py +++ b/algorithms/tree/min_height.py @@ -1,8 +1,4 @@ -class Node(): - def __init__(self, val = 0): - self.val = val - self.left = None - self.right = None +from tree.tree import TreeNode def min_depth(self, root): @@ -10,16 +6,16 @@ def min_depth(self, root): :type root: TreeNode :rtype: int """ - if not root: + if root is None: return 0 - if not root.left or not root.right: + if root.left is not None or root.right is not None: return max(self.minDepth(root.left), self.minDepth(root.right))+1 return min(self.minDepth(root.left), self.minDepth(root.right)) + 1 # iterative def min_height(root): - if not root: + if root is None: return 0 height = 0 level = [root] @@ -27,30 +23,32 @@ def min_height(root): height += 1 new_level = [] for node in level: - if not node.left and not node.right: + if node.left is None and node.right is None: return height - if node.left: + if node.left is not None: new_level.append(node.left) - if node.right: + if node.right is not None: new_level.append(node.right) level = new_level return height def print_tree(root): - if root: + if root is not None: print(root.val) print_tree(root.left) print_tree(root.right) -tree = Node(10) -tree.left = Node(12) -tree.right = Node(15) -tree.left.left = Node(25) -tree.left.left.right = Node(100) -tree.left.right = Node(30) -tree.right.left = Node(36) - -height = min_height(tree) -print_tree(tree) -print("height:", height) + +if __name__ == '__main__': + tree = TreeNode(10) + tree.left = TreeNode(12) + tree.right = TreeNode(15) + tree.left.left = TreeNode(25) + tree.left.left.right = TreeNode(100) + tree.left.right = TreeNode(30) + tree.right.left = TreeNode(36) + + height = min_height(tree) + print_tree(tree) + print("height:", height) diff --git a/algorithms/tree/path_sum.py b/algorithms/tree/path_sum.py index b1001c3a4..aa9ff87e7 100644 --- a/algorithms/tree/path_sum.py +++ b/algorithms/tree/path_sum.py @@ -21,9 +21,9 @@ def has_path_sum(root, sum): :type sum: int :rtype: bool """ - if not root: + if root is None: return False - if not root.left and not root.right and root.val == sum: + if root.left is None and root.right is None and root.val == sum: return True sum -= root.val return has_path_sum(root.left, sum) or has_path_sum(root.right, sum) @@ -31,33 +31,33 @@ def has_path_sum(root, sum): # DFS with stack def has_path_sum2(root, sum): - if not root: + if root is None: return False stack = [(root, root.val)] while stack: node, val = stack.pop() - if not node.left and not node.right: + if node.left is None and node.right is None: if val == sum: return True - if node.left: + if node.left is not None: stack.append((node.left, val+node.left.val)) - if node.right: + if node.right is not None: stack.append((node.right, val+node.right.val)) return False # BFS with queue def has_path_sum3(root, sum): - if not root: + if root is None: return False queue = [(root, sum-root.val)] while queue: node, val = queue.pop(0) # popleft - if not node.left and not node.right: + if node.left is None and node.right is None: if val == 0: return True - if node.left: + if node.left is not None: queue.append((node.left, val-node.left.val)) - if node.right: + if node.right is not None: queue.append((node.right, val-node.right.val)) return False diff --git a/algorithms/tree/path_sum2.py b/algorithms/tree/path_sum2.py index c989f9c18..f7c3e3fcf 100644 --- a/algorithms/tree/path_sum2.py +++ b/algorithms/tree/path_sum2.py @@ -20,51 +20,52 @@ def path_sum(root, sum): - if not root: + if root is None: return [] res = [] dfs(root, sum, [], res) return res + def dfs(root, sum, ls, res): - if not root.left and not root.right and root.val == sum: + if root.left is None and root.right is None and root.val == sum: ls.append(root.val) res.append(ls) - if root.left: + if root.left is not None: dfs(root.left, sum-root.val, ls+[root.val], res) - if root.right: + if root.right is not None: dfs(root.right, sum-root.val, ls+[root.val], res) # DFS with stack def path_sum2(root, s): - if not root: + if root is None: return [] res = [] stack = [(root, [root.val])] while stack: node, ls = stack.pop() - if not node.left and not node.right and sum(ls) == s: + if node.left is None and node.right is None and sum(ls) == s: res.append(ls) - if node.left: + if node.left is not None: stack.append((node.left, ls+[node.left.val])) - if node.right: + if node.right is not None: stack.append((node.right, ls+[node.right.val])) return res # BFS with queue def path_sum3(root, sum): - if not root: + if root is None: return [] res = [] queue = [(root, root.val, [root.val])] while queue: node, val, ls = queue.pop(0) # popleft - if not node.left and not node.right and val == sum: + if node.left is None and node.right is None and val == sum: res.append(ls) - if node.left: + if node.left is not None: queue.append((node.left, val+node.left.val, ls+[node.left.val])) - if node.right: + if node.right is not None: queue.append((node.right, val+node.right.val, ls+[node.right.val])) return res diff --git a/algorithms/tree/pretty_print.py b/algorithms/tree/pretty_print.py index 1e756470a..02fc0f027 100644 --- a/algorithms/tree/pretty_print.py +++ b/algorithms/tree/pretty_print.py @@ -8,6 +8,7 @@ # e -> Quin -> Book -> 5 # -> TV -> 2 # f -> Adam -> Computer -> 7 + from __future__ import print_function diff --git a/algorithms/tree/same_tree.py b/algorithms/tree/same_tree.py index a407f6fd3..7e87e7e08 100644 --- a/algorithms/tree/same_tree.py +++ b/algorithms/tree/same_tree.py @@ -8,9 +8,9 @@ def is_same_tree(p, q): - if not p and not q: + if p is None and q is None: return True - if p and q and p.val == q.val: + if p is not None and q is not None and p.val == q.val: return is_same_tree(p.left, q.left) and is_same_tree(p.right, q.right) return False diff --git a/algorithms/tree/tree.py b/algorithms/tree/tree.py index c286a72f6..6618ea036 100644 --- a/algorithms/tree/tree.py +++ b/algorithms/tree/tree.py @@ -3,6 +3,3 @@ def __init__(self, val=0): self.val = val self.left = None self.right = None - - - diff --git a/tests/test_dp.py b/tests/test_dp.py index e273f7479..2edaadfc3 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -21,14 +21,14 @@ class TestHosoyaTriangle(unittest.TestCase): """ def test_hosoya(self): - self.assertEqual([1], hosoya_testing(1)) + self.assertEqual([1], hosoya_triangle.hosoya_testing(1)) self.assertEqual([1, 1, 1, 2, 1, 2, 3, 2, 2, 3, 5, 3, 4, 3, 5, 8, 5, 6, 6, 5, 8], - hosoya_testing(6)) + hosoya_triangle.hosoya_testing(6)) self.assertEqual([1, 1, 1, 2, 1, 2, @@ -39,7 +39,7 @@ def test_hosoya(self): 21, 13, 16, 15, 15, 16, 13, 21, 34, 21, 26, 24, 25, 24, 26, 21, 34, 55, 34, 42, 39, 40, 40, 39, 42, 34, 55], - hosoya_testing(10)) + hosoya_triangle.hosoya_testing(10)) if __name__ == '__main__': diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 7c9aa0b3f..152727a78 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -8,7 +8,7 @@ class TestCroutMatrixDecomposition(unittest.TestCase): """[summary] - Test for the file crout_matrix_decomposition.py + Test for the file crout_matrix_decomposition.crout_matrix_decomposition.py Arguments: unittest {[type]} -- [description] @@ -17,7 +17,8 @@ class TestCroutMatrixDecomposition(unittest.TestCase): def test_crout_matrix_decomposition(self): self.assertEqual(([[9.0, 0.0], [7.0, 0.0]], [[1.0, 1.0], [0.0, 1.0]]), - crout_matrix_decomposition([[9,9], [7,7]])) + crout_matrix_decomposition.crout_matrix_decomposition( + [[9,9], [7,7]])) self.assertEqual(([[1.0, 0.0, 0.0], [3.0, -2.0, 0.0], @@ -25,7 +26,8 @@ def test_crout_matrix_decomposition(self): [[1.0, 2.0, 3.0], [0.0, 1.0, 2.0], [0.0, 0.0, 1.0]]), - crout_matrix_decomposition([[1,2,3],[3,4,5],[6,7,8]])) + crout_matrix_decomposition.crout_matrix_decomposition( + [[1,2,3],[3,4,5],[6,7,8]])) self.assertEqual(([[2.0, 0, 0, 0], [4.0, -1.0, 0, 0], @@ -35,10 +37,8 @@ def test_crout_matrix_decomposition(self): [0, 1.0, 2.0, 1.0], [0, 0, 1.0, 0.0], [0, 0, 0, 1.0]]), - crout_matrix_decomposition([[2,1,3,1], - [4,1,4,1], - [6,1,7,1], - [8,1,9,1]])) + crout_matrix_decomposition.crout_matrix_decomposition( + [[2,1,3,1], [4,1,4,1], [6,1,7,1], [8,1,9,1]])) diff --git a/tests/test_strings.py b/tests/test_strings.py index 66f91919d..02abc6f05 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -37,7 +37,7 @@ rotate, first_unique_char, repeat_substring, - atbash_cipher + atbash ) import unittest From 677ad091ef5e5d0d10f18e50e231ba89e4a13c65 Mon Sep 17 00:00:00 2001 From: Arnav Borborah Date: Fri, 15 Feb 2019 11:28:11 -0500 Subject: [PATCH 137/302] Remove the .vscode folder and add it to .gitignore (#478) --- .gitignore | 6 ++++-- .vscode/settings.json | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 99f920b84..fbcdee784 100755 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ __pycache__/ *.py[cod] -*.iml -*.xml +*.iml +*.xml .idea/ .cache/ .pytest_cache/ @@ -13,3 +13,5 @@ __pycache__/ /*.egg # docs build/ + +.vscode/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 9d17a2792..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.pythonPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\Python36_64\\python.exe" -} \ No newline at end of file From bab335a47869e5dbc62e18148fd0693e54f9e0fb Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Sat, 16 Feb 2019 00:28:30 +0800 Subject: [PATCH 138/302] update README.CN.md (#476) --- README_CN.md | 58 +++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/README_CN.md b/README_CN.md index aec110ad1..e0806be2e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -72,13 +72,13 @@ pip3 uninstall -y algorithms ## 实现列表 -- [array:数组](arrays) +- [array:数组](arrays) - [delete_nth: 删除第n项](algorithms/arrays/delete_nth.py) - [flatten:数组降维](algorithms/arrays/flatten.py) - [garage:停车场](algorithms/arrays/garage.py) - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus.py) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [limit](algorithms/arrays/limit.py) + - [max_ones_index:最长1串索引](algorithms/arrays/max_ones_index.py) + - [limit:数组过滤](algorithms/arrays/limit.py) - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) @@ -86,12 +86,14 @@ pip3 uninstall -y algorithms - [rotate:反转数组](algorithms/arrays/rotate.py) - [summarize_ranges:数组范围](algorithms/arrays/summarize_ranges.py) - [three_sum:三数和为零](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) + - [trimmean:按比取均值](algorithms/arrays/trimmean.py) + - [top_1:出现次数最多的元素](algorithms/arrays/top_1.py) - [two_sum:两数和](algorithms/arrays/two_sum.py) - [move_zeros: 0后置问题](algorithms/arrays/move_zeros.py) + - [n_sum](algorithms/arrays/n_sum.py) - [backtrack:回溯](algorithms/backtrack) - [general_solution.md:一般方法](algorithms/backtrack/) + - [add_operators:](algorithms/backtrack/add_operators.py) - [anagram:同字母异序词](algorithms/backtrack/anagram.py) - [array_sum_combinations:数组和](algorithms/backtrack/array_sum_combinations.py) - [combination_sum:和的合并](algorithms/backtrack/combination_sum.py) @@ -107,19 +109,19 @@ pip3 uninstall -y algorithms - [subsets:子集](algorithms/backtrack/subsets.py) - [subsets_unique:唯一子集](algorithms/backtrack/subsets_unique.py) - [bfs:广度优先搜索](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings:所有建筑物的最短路径:](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [maze_search:迷宫的最短路径](algorithms/bfs/maze_search.py) + - [shortest_distance_from_all_buildings:所有建筑物的最短路径](algorithms/bfs/shortest_distance_from_all_buildings.py) - [word_ladder:词语阶梯](algorithms/bfs/word_ladder.py) - [bit:位操作](algorithms/bit) - [bytes_int_conversion:字节整数转换](algorithms/bit/bytes_int_conversion.py) - [count_ones:统计1出现的次数](algorithms/bit/count_ones.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) + - [count_flips_to_convert:不同的比特位](algorithms/bit/count_flips_to_convert.py) - [find_missing_number:寻找缺失数](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) + - [flip_bit_longest_sequence:最长1串长度](algorithms/bit/flip_bit_longest_sequence.py) - [power_of_two:2的n次方数判断](algorithms/bit/power_of_two.py) - [reverse_bits:反转位](algorithms/bit/reverse_bits.py) - - [single_number2:寻找出现1次的数(2)](algorithms/bit/single_number2.py) - - [single_number:寻找出现1次的数(1)](algorithms/bit/single_number.py) + - [single_number2:寻找出现1次的数(2)](algorithms/bit/single_number2.py) + - [single_number:寻找出现1次的数(1)](algorithms/bit/single_number.py) - [subsets: 求所有子集](algorithms/bit/subsets.py) - [add_bitwise_operator:无操作符的加法](algorithms/bit/add_bitwise_operator.py) - [calculator:计算](algorithms/calculator) @@ -143,7 +145,7 @@ pip3 uninstall -y algorithms - [regex_matching:正则匹配](algorithms/dp/regex_matching.py) - [word_break:单词分割](algorithms/dp/word_break.py) - [graph:图](graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) + - [check_bipartite:二分图](algorithms/graph/check_bipartite.py) - [2-sat:2-sat](algorithms/graph/satisfiability.py) - [clone_graph:克隆图](algorithms/graph/clone_graph.py) - [cycle_detection:判断圈算法](algorithms/graph/cycle_detection.py) @@ -176,14 +178,14 @@ pip3 uninstall -y algorithms - [valid_sudoku:有效数独](algorithms/map/valid_sudoku.py) - [math:数学问题](algorithms/maths) - [extended_gcd:扩展欧几里得算法](algorithms/maths/extended_gcd.py) - - [combination](algorithms/maths/combination.py) - - [factorial](algorithms/maths/factorial.py) + - [combination:组合数](algorithms/maths/combination.py) + - [factorial:阶乘](algorithms/maths/factorial.py) - [gcd/lcm:最大公约数和最小公倍数](algorithms/maths/gcd.py) - [prime_test:主要测试](algorithms/maths/prime_test.py) - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](algorithms/maths/primes_sieve_of_eratosthenes.py) - [generate_strobogrammtic:生成对称数](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic:判断对称数](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) + - [modular_exponential:m的n次方](algorithms/maths/modular_exponential.py) - [nth_digit:第n位](algorithms/maths/nth_digit.py) - [rabin_miller:米勒-拉宾素性检验](algorithms/maths/rabin_miller.py) - [rsa:rsa加密](algorithms/maths/rsa.py) @@ -209,30 +211,30 @@ pip3 uninstall -y algorithms - [count_elem:元素计数](algorithms/search/count_elem.py) - [first_occurance:首次出现](algorithms/search/first_occurance.py) - [last_occurance:最后一次出现](algorithms/search/last_occurance.py) - - [linear_search](algorithms/search/linear_search.py) - - [jump_search](algorithms/search/jump_search.py) + - [linear_search:线性搜索](algorithms/search/linear_search.py) + - [jump_search:跳跃搜索](algorithms/search/jump_search.py) - [set:集合](algorithms/set) - [randomized_set:随机集合](algorithms/set/randomized_set.py) - [set_covering:集合覆盖](algorithms/set/set_covering.py) - [sort:排序](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) + - [bitonic_sort:双调排序](algorithms/sort/bitonic_sort.py) + - [bogo_sort:猴子排序](algorithms/sort/bogo_sort.py) - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) + - [bucket_sort:桶排序](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort:鸡尾酒排序](algorithms/sort/cocktail_shaker_sort.py) - [comb_sort:梳排序](algorithms/sort/comb_sort.py) - [counting_sort:计数排序](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) + - [cycle_sort:圈排序](algorithms/sort/cycle_sort.py) + - [gnome_sort:地精排序](algorithms/sort/gnome_sort.py) - [heap_sort:堆排序](algorithms/sort/heap_sort.py) - [insertion_sort:插入排序](algorithms/sort/insertion_sort.py) - [meeting_rooms:会议室](algorithms/sort/meeting_rooms.py) - [merge_sort:归并排序](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) + - [pancake_sort:煎饼排序](algorithms/sort/pancake_sort.py) - [quick_sort:快速排序](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) + - [radix_sort:基数排序](algorithms/sort/radix_sort.py) - [selection_sort:选择排序](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) + - [shell_sort:希尔排序](algorithms/sort/shell_sort.py) - [sort_colors:颜色排序](algorithms/sort/sort_colors.py) - [top_sort:top排序](algorithms/sort/top_sort.py) - [wiggle_sort:摇摆排序](algorithms/sort/wiggle_sort.py) @@ -293,8 +295,8 @@ pip3 uninstall -y algorithms - [traversal:遍历](algorithms/tree/traversal) - [inorder:中序遍历](algorithms/tree/traversal/inorder.py) - [level_order:层次遍历](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) + - [postorder:后序遍历](algorithms/tree/traversal/postorder.py) + - [preorder:前序遍历](algorithms/tree/traversal/preorder.py) - [zigzag:锯齿形遍历](algorithms/tree/traversal/zigzag.py) - [tree:树](algorithms/tree/tree.py) - [trie:字典树](algorithms/tree/trie) From 7a4de8dd99f720cabd5b085a421257fa88ca15c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=84=E8=99=9A?= Date: Sat, 16 Feb 2019 00:29:24 +0800 Subject: [PATCH 139/302] fix a error in is_bst.py (#474) --- algorithms/tree/bst/is_bst.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/algorithms/tree/bst/is_bst.py b/algorithms/tree/bst/is_bst.py index a132a5af3..ad3adc601 100644 --- a/algorithms/tree/bst/is_bst.py +++ b/algorithms/tree/bst/is_bst.py @@ -20,17 +20,16 @@ Binary tree [1,2,3], return false. """ - def is_bst(root): """ :type root: TreeNode :rtype: bool """ - if not root: - return True + stack = [] pre = None - while root and stack: + + while root or stack: while root: stack.append(root) root = root.left @@ -39,4 +38,5 @@ def is_bst(root): return False pre = root root = root.right + return True From f4b346c78ec92376b264e64be4b11ae36e621074 Mon Sep 17 00:00:00 2001 From: Sushmith Date: Fri, 15 Feb 2019 22:00:08 +0530 Subject: [PATCH 140/302] Add test cases for inorder traversal (#473) * Add test cases for inorder traversal * Fix k_closest_points test cases --- tests/test_heap.py | 8 +++--- tests/test_tree.py | 64 ++++++++++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/tests/test_heap.py b/tests/test_heap.py index 6814c6196..f445f2cfd 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -56,11 +56,11 @@ def test_max_sliding_window(self): def test_k_closest_points(self): points = [(1, 0), (2, 3), (5, 2), (1, 1), (2, 8), (10, 2), (-1, 0), (-2, -2)] - self.assertEqual([(-1, 0), (1, 0)], k_closest(points, 2)) - self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest(points, 3)) - self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest(points, 4)) + self.assertEqual([(-1, 0), (1, 0)], k_closest_points.k_closest(points, 2)) + self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest_points.k_closest(points, 3)) + self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest_points.k_closest(points, 4)) self.assertEqual([(10, 2), (2, 8), (5, 2), (-2, -2), (2, 3), - (1, 0), (-1, 0), (1, 1)], k_closest(points, 8)) + (1, 0), (-1, 0), (1, 1)], k_closest_points.k_closest(points, 8)) if __name__ == "__main__": diff --git a/tests/test_tree.py b/tests/test_tree.py index a9d53ca6d..1fbcd6a2e 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -2,45 +2,53 @@ preorder, preorder_rec, postorder, - postorder_rec + postorder_rec, + inorder, + inorder_rec ) import unittest + class Node: def __init__(self, val, left=None, right=None): self.val = val self.left = left self.right = right - + class TestTraversal(unittest.TestCase): - + def test_preorder(self): - n1 = Node(100) - n2 = Node(50) - n3 = Node(150) - n4 = Node(25) - n5 = Node(75) - n6 = Node(125) - n7 = Node(175) - n1.left, n1.right = n2, n3 - n2.left, n2.right = n4, n5 - n3.left, n3.right = n6, n7 - self.assertEqual([100, 50, 25, 75, 150, 125, 175], preorder(n1)) - self.assertEqual([100, 50, 25, 75, 150, 125, 175], preorder_rec(n1)) - + tree = create_tree() + self.assertEqual([100, 50, 25, 75, 150, 125, 175], preorder(tree)) + self.assertEqual([100, 50, 25, 75, 150, 125, 175], preorder_rec(tree)) + def test_postorder(self): - n1 = Node(100) - n2 = Node(50) - n3 = Node(150) - n4 = Node(25) - n5 = Node(75) - n6 = Node(125) - n7 = Node(175) - n1.left, n1.right = n2, n3 - n2.left, n2.right = n4, n5 - n3.left, n3.right = n6, n7 - self.assertEqual([25, 75, 50, 125, 175, 150, 100], postorder(n1)) - self.assertEqual([25, 75, 50, 125, 175, 150, 100], postorder_rec(n1)) + tree = create_tree() + self.assertEqual([25, 75, 50, 125, 175, 150, 100], postorder(tree)) + self.assertEqual([25, 75, 50, 125, 175, 150, 100], postorder_rec(tree)) + + def test_inorder(self): + tree = create_tree() + self.assertEqual([25, 50, 75, 100, 125, 150, 175], inorder(tree)) + self.assertEqual([25, 50, 75, 100, 125, 150, 175], inorder_rec(tree)) + + +def create_tree(): + n1 = Node(100) + n2 = Node(50) + n3 = Node(150) + n4 = Node(25) + n5 = Node(75) + n6 = Node(125) + n7 = Node(175) + n1.left, n1.right = n2, n3 + n2.left, n2.right = n4, n5 + n3.left, n3.right = n6, n7 + return n1 + + +if __name__ == '__main__': + unittest.main() From 3e6c93a026bcc6de9cd88b19bed186bded61fcbf Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Thu, 7 Mar 2019 11:38:43 +0800 Subject: [PATCH 141/302] fix: test_heap, tree/traversal/__init__ (#481) * fix: test_heap, tree/traversal/__init__ * fix a error in longest_non_repeat.py --- algorithms/arrays/longest_non_repeat.py | 14 ++++++++++---- algorithms/tree/traversal/__init__.py | 1 + tests/test_heap.py | 8 ++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/algorithms/arrays/longest_non_repeat.py b/algorithms/arrays/longest_non_repeat.py index cad3d2430..c3ba8150d 100644 --- a/algorithms/arrays/longest_non_repeat.py +++ b/algorithms/arrays/longest_non_repeat.py @@ -53,14 +53,17 @@ def get_longest_non_repeat_v1(string): """ if string is None: return 0 + sub_string = '' temp = [] max_len = 0 for i in string: if i in temp: temp = [] temp.append(i) - max_len = max(max_len, len(temp)) - return max_len, temp + if len(temp) > max_len: + max_len = len(temp) + sub_string = ''.join(temp) + return max_len, sub_string def get_longest_non_repeat_v2(string): """ @@ -71,12 +74,15 @@ def get_longest_non_repeat_v2(string): """ if string is None: return 0 + sub_string = '' start, max_len = 0, 0 used_char = {} for index, char in enumerate(string): if char in used_char and start <= used_char[char]: start = used_char[char] + 1 else: - max_len = max(max_len, index - start + 1) + if index - start + 1 > max_len: + max_len = index - start + 1 + sub_string = string[start: index + 1] used_char[char] = index - return max_len, start \ No newline at end of file + return max_len, sub_string \ No newline at end of file diff --git a/algorithms/tree/traversal/__init__.py b/algorithms/tree/traversal/__init__.py index df3c88c05..d5babeefd 100644 --- a/algorithms/tree/traversal/__init__.py +++ b/algorithms/tree/traversal/__init__.py @@ -1,2 +1,3 @@ from .preorder import * from .postorder import * +from .inorder import * diff --git a/tests/test_heap.py b/tests/test_heap.py index f445f2cfd..6814c6196 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -56,11 +56,11 @@ def test_max_sliding_window(self): def test_k_closest_points(self): points = [(1, 0), (2, 3), (5, 2), (1, 1), (2, 8), (10, 2), (-1, 0), (-2, -2)] - self.assertEqual([(-1, 0), (1, 0)], k_closest_points.k_closest(points, 2)) - self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest_points.k_closest(points, 3)) - self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest_points.k_closest(points, 4)) + self.assertEqual([(-1, 0), (1, 0)], k_closest(points, 2)) + self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest(points, 3)) + self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest(points, 4)) self.assertEqual([(10, 2), (2, 8), (5, 2), (-2, -2), (2, 3), - (1, 0), (-1, 0), (1, 1)], k_closest_points.k_closest(points, 8)) + (1, 0), (-1, 0), (1, 1)], k_closest(points, 8)) if __name__ == "__main__": From f438cd39375bcba65cb594cb37290f0aa9cd69e5 Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Fri, 8 Mar 2019 13:02:40 +0800 Subject: [PATCH 142/302] fix bugs, add descriptions, and add tests (#486) * fix: test_heap, tree/traversal/__init__ * fix a error in longest_non_repeat.py * fix bugs, add notes, and add tests --- algorithms/arrays/longest_non_repeat.py | 27 +++--- algorithms/backtrack/anagram.py | 9 ++ .../backtrack/generate_abbreviations.py | 2 +- algorithms/backtrack/letter_combination.py | 10 +++ tests/test_array.py | 38 ++++++++- tests/test_backtrack.py | 84 ++++++++++++++++++- 6 files changed, 153 insertions(+), 17 deletions(-) diff --git a/algorithms/arrays/longest_non_repeat.py b/algorithms/arrays/longest_non_repeat.py index c3ba8150d..786c03dfe 100644 --- a/algorithms/arrays/longest_non_repeat.py +++ b/algorithms/arrays/longest_non_repeat.py @@ -16,6 +16,8 @@ def longest_non_repeat_v1(string): Find the length of the longest substring without repeating characters. """ + if string is None: + return 0 dict = {} max_length = 0 j = 0 @@ -52,18 +54,19 @@ def get_longest_non_repeat_v1(string): Return max_len and the substring as a tuple """ if string is None: - return 0 + return 0, '' sub_string = '' - temp = [] - max_len = 0 - for i in string: - if i in temp: - temp = [] - temp.append(i) - if len(temp) > max_len: - max_len = len(temp) - sub_string = ''.join(temp) - return max_len, sub_string + dict = {} + max_length = 0 + j = 0 + for i in range(len(string)): + if string[i] in dict: + j = max(dict[string[i]], j) + dict[string[i]] = i + 1 + if i - j + 1 > max_length: + max_length = i - j + 1 + sub_string = string[j: i + 1] + return max_length, sub_string def get_longest_non_repeat_v2(string): """ @@ -73,7 +76,7 @@ def get_longest_non_repeat_v2(string): Return max_len and the substring as a tuple """ if string is None: - return 0 + return 0, '' sub_string = '' start, max_len = 0, 0 used_char = {} diff --git a/algorithms/backtrack/anagram.py b/algorithms/backtrack/anagram.py index 7c807cdbd..df3f4ab57 100644 --- a/algorithms/backtrack/anagram.py +++ b/algorithms/backtrack/anagram.py @@ -1,3 +1,12 @@ +""" +Given two strings, determine if they are equal after reordering. + +Examples: +"apple", "pleap" -> True +"apple", "cherry" -> False +""" + + def anagram(s1, s2): c1 = [0] * 26 c2 = [0] * 26 diff --git a/algorithms/backtrack/generate_abbreviations.py b/algorithms/backtrack/generate_abbreviations.py index 132965687..674df93af 100644 --- a/algorithms/backtrack/generate_abbreviations.py +++ b/algorithms/backtrack/generate_abbreviations.py @@ -1,7 +1,7 @@ """ given input word, return the list of abbreviations. ex) -word => [1ord, w1rd, wo1d, w2d, 3d, w3 ... etc] +word => ['word', 'wor1', 'wo1d', 'wo2', 'w1rd', 'w1r1', 'w2d', 'w3', '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4'] """ diff --git a/algorithms/backtrack/letter_combination.py b/algorithms/backtrack/letter_combination.py index 8a2f8d151..09f8af826 100644 --- a/algorithms/backtrack/letter_combination.py +++ b/algorithms/backtrack/letter_combination.py @@ -2,6 +2,16 @@ Given a digit string, return all possible letter combinations that the number could represent. +A mapping of digit to letters (just like on the telephone buttons) is given below: +2: "abc" +3: "def" +4: "ghi" +5: "jkl" +6: "mno" +7: "pqrs" +8: "tuv" +9: "wxyz" + Input:Digit string "23" Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. """ diff --git a/tests/test_array.py b/tests/test_array.py index 3fd6e0882..c02b2754e 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -3,7 +3,7 @@ flatten_iter, flatten, garage, josephus, - longest_non_repeat_v1, longest_non_repeat_v2, + longest_non_repeat_v1, longest_non_repeat_v2, get_longest_non_repeat_v1, get_longest_non_repeat_v2, Interval, merge_intervals, missing_ranges, move_zeros, @@ -169,6 +169,40 @@ def test_longest_non_repeat_v2(self): string = "asjrgapa" self.assertEqual(longest_non_repeat_v2(string), 6) + + def test_get_longest_non_repeat_v1(self): + + string = "abcabcbb" + self.assertEqual(get_longest_non_repeat_v1(string), (3, 'abc')) + + string = "bbbbb" + self.assertEqual(get_longest_non_repeat_v1(string), (1, 'b')) + + string = "pwwkew" + self.assertEqual(get_longest_non_repeat_v1(string), (3, 'wke')) + + string = "dvdf" + self.assertEqual(get_longest_non_repeat_v1(string), (3, 'vdf')) + + string = "asjrgapa" + self.assertEqual(get_longest_non_repeat_v1(string), (6, 'sjrgap')) + + def test_get_longest_non_repeat_v2(self): + + string = "abcabcbb" + self.assertEqual(get_longest_non_repeat_v2(string), (3, 'abc')) + + string = "bbbbb" + self.assertEqual(get_longest_non_repeat_v2(string), (1, 'b')) + + string = "pwwkew" + self.assertEqual(get_longest_non_repeat_v2(string), (3, 'wke')) + + string = "dvdf" + self.assertEqual(get_longest_non_repeat_v2(string), (3, 'vdf')) + + string = "asjrgapa" + self.assertEqual(get_longest_non_repeat_v2(string), (6, 'sjrgap')) class TestMaxOnesIndex(unittest.TestCase): @@ -314,7 +348,7 @@ def test_three_sum(self): {(-4, 1, 3), (-2, -1, 3), (-1, -1, 2)}) -class TestSuite(unittest.TestCase): +class TestTwoSum(unittest.TestCase): def test_two_sum(self): diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py index c53f9f1e1..cb0838a05 100644 --- a/tests/test_backtrack.py +++ b/tests/test_backtrack.py @@ -6,12 +6,17 @@ array_sum_combinations, unique_array_sum_combinations, combination_sum, + get_factors, + recursive_get_factors, find_words, + generate_abbreviations, + generate_parenthesis_v1, + generate_parenthesis_v2, + letter_combinations, pattern_match, ) import unittest -from algorithms.backtrack.generate_parenthesis import * class TestAddOperator(unittest.TestCase): @@ -110,6 +115,53 @@ def test_combination_sum(self): self.assertEqual(combination_sum(candidates2, target2), answer2) +class TestFactorCombinations(unittest.TestCase): + + def test_get_factors(self): + target1 = 32 + answer1 = [ + [2, 16], + [2, 2, 8], + [2, 2, 2, 4], + [2, 2, 2, 2, 2], + [2, 4, 4], + [4, 8] + ] + self.assertEqual(sorted(get_factors(target1)), sorted(answer1)) + + target2 = 12 + answer2 = [ + [2, 6], + [2, 2, 3], + [3, 4] + ] + self.assertEqual(sorted(get_factors(target2)), sorted(answer2)) + self.assertEqual(sorted(get_factors(1)), []) + self.assertEqual(sorted(get_factors(37)), []) + + def test_recursive_get_factors(self): + target1 = 32 + answer1 = [ + [2, 16], + [2, 2, 8], + [2, 2, 2, 4], + [2, 2, 2, 2, 2], + [2, 4, 4], + [4, 8] + ] + self.assertEqual(sorted(recursive_get_factors(target1)), sorted(answer1)) + + target2 = 12 + answer2 = [ + [2, 6], + [2, 2, 3], + [3, 4] + ] + self.assertEqual(sorted(recursive_get_factors(target2)), sorted(answer2)) + self.assertEqual(sorted(recursive_get_factors(1)), []) + self.assertEqual(sorted(recursive_get_factors(37)), []) + + class TestFindWords(unittest.TestCase): def test_normal(self): @@ -158,6 +210,21 @@ def test_repeat(self): self.assertTrue(len(find_words(board, words)) == 5) +class TestGenerateAbbreviations(unittest.TestCase): + def test_generate_abbreviations(self): + word1 = "word" + answer1 = ['word', 'wor1', 'wo1d', 'wo2', 'w1rd', 'w1r1', 'w2d', 'w3', + '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4'] + self.assertEqual(sorted(generate_abbreviations(word1)), sorted(answer1)) + + word2 = "hello" + answer2 = ['hello', 'hell1', 'hel1o', 'hel2', 'he1lo', 'he1l1', 'he2o', + 'he3', 'h1llo', 'h1ll1', 'h1l1o', 'h1l2', 'h2lo', 'h2l1', 'h3o', 'h4', + '1ello', '1ell1', '1el1o', '1el2', '1e1lo', '1e1l1', '1e2o', '1e3', + '2llo', '2ll1', '2l1o', '2l2', '3lo', '3l1', '4o', '5'] + self.assertEqual(sorted(generate_abbreviations(word2)), sorted(answer2)) + + class TestPatternMatch(unittest.TestCase): def test_pattern_match(self): @@ -172,6 +239,7 @@ def test_pattern_match(self): self.assertTrue(pattern_match(pattern2, string2)) self.assertFalse(pattern_match(pattern3, string3)) + class TestGenerateParenthesis(unittest.TestCase): def test_generate_parenthesis(self): @@ -180,7 +248,19 @@ def test_generate_parenthesis(self): self.assertEqual(generate_parenthesis_v2(2), ['(())', '()()']) self.assertEqual(generate_parenthesis_v2(3), ['((()))', '(()())', '(())()', '()(())', '()()()']) + +class TestLetterCombinations(unittest.TestCase): + + def test_letter_combinations(self): + digit1 = "23" + answer1 = ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"] + self.assertEqual(sorted(letter_combinations(digit1)), sorted(answer1)) + + digit2 = "34" + answer2 = ['dg', 'dh', 'di', 'eg', 'eh', 'ei', 'fg', 'fh', 'fi'] + self.assertEqual(sorted(letter_combinations(digit2)), sorted(answer2)) + + if __name__ == '__main__': unittest.main() - From e1eb4bda0d2e26dfd644707375ddafb46ca0256b Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Tue, 26 Mar 2019 11:29:26 +0800 Subject: [PATCH 143/302] fix bugs, add descriptions, and add tests (#487) * fix: test_heap, tree/traversal/__init__ * fix a error in longest_non_repeat.py * fix bugs, add notes, and add tests * fix bugs, add descriptions, and add tests * fix bugs, add descriptions, and add tests --- .../backtrack/palindrome_partitioning.py | 3 + algorithms/backtrack/permute.py | 2 +- algorithms/backtrack/subsets.py | 2 +- tests/test_backtrack.py | 107 ++++++++++++++++++ 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/algorithms/backtrack/palindrome_partitioning.py b/algorithms/backtrack/palindrome_partitioning.py index 052339dcc..10f1da94d 100644 --- a/algorithms/backtrack/palindrome_partitioning.py +++ b/algorithms/backtrack/palindrome_partitioning.py @@ -3,6 +3,9 @@ up into palindromic substrings. (There's always at least one way, since one-character substrings are always palindromes.) + +ex) +'abcbab' => [['abcba', 'b'], ['a', 'bcb', 'a', 'b'], ['a', 'b', 'c', 'bab'], ['a', 'b', 'c', 'b', 'a', 'b']] """ diff --git a/algorithms/backtrack/permute.py b/algorithms/backtrack/permute.py index 4ce484369..27c7d972f 100644 --- a/algorithms/backtrack/permute.py +++ b/algorithms/backtrack/permute.py @@ -19,7 +19,7 @@ def permute(elements): returns a list with the permuations. """ if len(elements) <= 1: - return elements + return [elements] else: tmp = [] for perm in permute(elements[1:]): diff --git a/algorithms/backtrack/subsets.py b/algorithms/backtrack/subsets.py index 1c443024f..56eef44e8 100644 --- a/algorithms/backtrack/subsets.py +++ b/algorithms/backtrack/subsets.py @@ -52,7 +52,7 @@ def backtrack(res, nums, cur, pos): # Iteratively -def subsets_v2(self, nums): +def subsets_v2(nums): res = [[]] for num in sorted(nums): res += [item+[num] for item in res] diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py index cb0838a05..682a89b04 100644 --- a/tests/test_backtrack.py +++ b/tests/test_backtrack.py @@ -13,7 +13,14 @@ generate_parenthesis_v1, generate_parenthesis_v2, letter_combinations, + palindromic_substrings, pattern_match, + permute_unique, + permute, + permute_recursive, + subsets_unique, + subsets, + subsets_v2, ) import unittest @@ -261,6 +268,106 @@ def test_letter_combinations(self): self.assertEqual(sorted(letter_combinations(digit2)), sorted(answer2)) +class TestPalindromicSubstrings(unittest.TestCase): + + def test_palindromic_substrings(self): + string1 = "abc" + answer1 = [['a', 'b', 'c']] + self.assertEqual(palindromic_substrings(string1), sorted(answer1)) + + string2 = "abcba" + answer2 = [['abcba'], ['a', 'bcb', 'a'], ['a', 'b', 'c', 'b', 'a']] + self.assertEqual(sorted(palindromic_substrings(string2)), sorted(answer2)) + + string3 = "abcccba" + answer3 = [['abcccba'], ['a', 'bcccb', 'a'], ['a', 'b', 'ccc', 'b', 'a'], + ['a', 'b', 'cc', 'c', 'b', 'a'], ['a', 'b', 'c', 'cc', 'b', 'a'], + ['a', 'b', 'c', 'c', 'c', 'b', 'a']] + self.assertEqual(sorted(palindromic_substrings(string3)), sorted(answer3)) + + +class TestPermuteUnique(unittest.TestCase): + + def test_permute_unique(self): + nums1 = [1, 1, 2] + answer1 = [[2, 1, 1], [1, 2, 1], [1, 1, 2]] + self.assertEqual(sorted(permute_unique(nums1)), sorted(answer1)) + + nums2 = [1, 2, 1, 3] + answer2 = [[3, 1, 2, 1], [1, 3, 2, 1], [1, 2, 3, 1], [1, 2, 1, 3], [3, 2, 1, 1], + [2, 3, 1, 1], [2, 1, 3, 1], [2, 1, 1, 3], [3, 1, 1, 2], [1, 3, 1, 2], [1, 1, 3, 2], [1, 1, 2, 3]] + self.assertEqual(sorted(permute_unique(nums2)), sorted(answer2)) + + nums3 = [1, 2, 3] + answer3 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]] + self.assertEqual(sorted(permute_unique(nums3)), sorted(answer3)) + + +class TestPermute(unittest.TestCase): + + def test_permute(self): + nums1 = [1, 2, 3, 4] + answer1 = [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1], [1, 3, 2, 4], + [3, 1, 2, 4], [3, 2, 1, 4], [3, 2, 4, 1], [1, 3, 4, 2], [3, 1, 4, 2], + [3, 4, 1, 2], [3, 4, 2, 1], [1, 2, 4, 3], [2, 1, 4, 3], [2, 4, 1, 3], + [2, 4, 3, 1], [1, 4, 2, 3], [4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], + [1, 4, 3, 2], [4, 1, 3, 2], [4, 3, 1, 2], [4, 3, 2, 1]] + self.assertEqual(sorted(permute(nums1)), sorted(answer1)) + + nums2 = [1, 2, 3] + answer2 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]] + self.assertEqual(sorted(permute(nums2)), sorted(answer2)) + + def test_permute_recursive(self): + nums1 = [1, 2, 3, 4] + answer1 = [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1], [1, 3, 2, 4], + [3, 1, 2, 4], [3, 2, 1, 4], [3, 2, 4, 1], [1, 3, 4, 2], [3, 1, 4, 2], + [3, 4, 1, 2], [3, 4, 2, 1], [1, 2, 4, 3], [2, 1, 4, 3], [2, 4, 1, 3], + [2, 4, 3, 1], [1, 4, 2, 3], [4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], + [1, 4, 3, 2], [4, 1, 3, 2], [4, 3, 1, 2], [4, 3, 2, 1]] + self.assertEqual(sorted(permute_recursive(nums1)), sorted(answer1)) + + nums2 = [1, 2, 3] + answer2 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]] + self.assertEqual(sorted(permute_recursive(nums2)), sorted(answer2)) + + +class TestSubsetsUnique(unittest.TestCase): + + def test_subsets_unique(self): + nums1 = [1, 2, 2] + answer1 = [(1, 2), (1,), (1, 2, 2), (2,), (), (2, 2)] + self.assertEqual(sorted(subsets_unique(nums1)), sorted(answer1)) + + nums2 = [1, 2, 3, 4] + answer2 = [(1, 2), (1, 3), (1, 2, 3, 4), (1,), (2,), (3,), (1, 4), (1, 2, 3), + (4,), (), (2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (3, 4), (2, 4)] + self.assertEqual(sorted(subsets_unique(nums2)), sorted(answer2)) + + +class TestSubsets(unittest.TestCase): + + def test_subsets(self): + nums1 = [1, 2, 3] + answer1 = [[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []] + self.assertEqual(sorted(subsets(nums1)), sorted(answer1)) + + nums2 = [1, 2, 3, 4] + answer2 = [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], + [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], [3, 4], [3], [4], []] + self.assertEqual(sorted(subsets(nums2)), sorted(answer2)) + + def test_subsets_v2(self): + nums1 = [1, 2, 3] + answer1 = [[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []] + self.assertEqual(sorted(subsets_v2(nums1)), sorted(answer1)) + + nums2 = [1, 2, 3, 4] + answer2 = [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], + [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], [3, 4], [3], [4], []] + self.assertEqual(sorted(subsets_v2(nums2)), sorted(answer2)) + + if __name__ == '__main__': unittest.main() From 006cefd9fc405188846f0675b51a9e4a60b3cd35 Mon Sep 17 00:00:00 2001 From: Guillaume Chevalier Date: Mon, 25 Mar 2019 23:31:01 -0400 Subject: [PATCH 144/302] Add `convolve` iteration algorithm with tests (#428) * added convolve algorithm with tests * Fixed tox.ini * Removed dependency --- README.md | 2 + README_CN.md | 2 + README_FR.md | 2 + README_GE.md | 2 + README_JP.md | 2 + README_KR.md | 2 + README_PTBR.md | 2 + algorithms/iterables/__init__.py | 1 + algorithms/iterables/convolved.py | 154 ++++++++++++++++++++++++++++ tests/test_iterables.py | 161 ++++++++++++++++++++++++++++++ tree.md | 5 +- 11 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 algorithms/iterables/__init__.py create mode 100644 algorithms/iterables/convolved.py create mode 100644 tests/test_iterables.py diff --git a/README.md b/README.md index 13f760602..48d4c7f7c 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,8 @@ If you want to uninstall algorithms, it is as simple as: - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) +- [iterables](algorithms/iterables) + - [convolved](algorithms/iterables/convolved.py) - [k_closest_points](algorithms/heap/k_closest_points.py) - [linkedlist](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) diff --git a/README_CN.md b/README_CN.md index e0806be2e..ca181d613 100644 --- a/README_CN.md +++ b/README_CN.md @@ -157,6 +157,8 @@ pip3 uninstall -y algorithms - [merge_sorted_k_lists:合并k个有序链](algorithms/heap/merge_sorted_k_lists.py) - [skyline:天际线](algorithms/heap/skyline.py) - [sliding_window_max:滑动窗口最大值](algorithms/heap/sliding_window_max.py) +- [iterables : 迭代](algorithms/iterables) + - [convolved : 卷积](algorithms/iterables/convolved.py) - [linkedlist:链表](algorithms/linkedlist) - [add_two_numbers:链表数相加](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer:复制带有随机指针的链表](algorithms/linkedlist/copy_random_pointer.py) diff --git a/README_FR.md b/README_FR.md index fc6d41f7a..99d445ad7 100644 --- a/README_FR.md +++ b/README_FR.md @@ -158,6 +158,8 @@ Si vous voulez désinstaller le paquet algorithms, il suffit de procéder comme - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) +- [iterables](algorithms/iterables) + - [convolved](algorithms/iterables/convolved.py) - [linkedlist](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) diff --git a/README_GE.md b/README_GE.md index ab68bdda2..91883c8ff 100644 --- a/README_GE.md +++ b/README_GE.md @@ -165,6 +165,8 @@ Um das Projekt zu deinstallieren tippen Sie folgendes: - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) +- [iterables](algorithms/iterables) + - [convolved](algorithms/iterables/convolved.py) - [linkedlist](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) diff --git a/README_JP.md b/README_JP.md index ca31babbb..28f29cba8 100644 --- a/README_JP.md +++ b/README_JP.md @@ -159,6 +159,8 @@ if __name__ == "__main__": - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) +- [iterables : 繰り返し可能な](algorithms/iterables) + - [convolved](algorithms/iterables/convolved.py) - [linkedlist : 連結リスト](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) diff --git a/README_KR.md b/README_KR.md index f0f583e4c..ab4ce7790 100644 --- a/README_KR.md +++ b/README_KR.md @@ -155,6 +155,8 @@ if __name__ == "__main__": - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) +- [iterable : 반복 가능한 것](algorithms/iterables) + - [convolved](algorithms/iterables/convolved.py) - [linkedlist : 연결 리스트](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) diff --git a/README_PTBR.md b/README_PTBR.md index a93f45d03..c8bed5417 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -157,6 +157,8 @@ Se você deseja desinstalar os algoritmos, é tão simples quanto: - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) +- [iterables](algorithms/iterables) + - [convolved](algorithms/iterables/convolved.py) - [linkedlist](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) diff --git a/algorithms/iterables/__init__.py b/algorithms/iterables/__init__.py new file mode 100644 index 000000000..f39a0ffd5 --- /dev/null +++ b/algorithms/iterables/__init__.py @@ -0,0 +1 @@ +from .convolved import * diff --git a/algorithms/iterables/convolved.py b/algorithms/iterables/convolved.py new file mode 100644 index 000000000..4f8b49288 --- /dev/null +++ b/algorithms/iterables/convolved.py @@ -0,0 +1,154 @@ +"""Iterable to get every convolution window per loop iteration. + +## Example Usage + +``` +from algorithms.iterables import convolved +# This would also work: from conv import convolved + +some_list = [1, 2, 3] +for kernel_hover in convolved(some_list, kernel_size=2, stride=1, padding=2, default_value=42): + print(kernel_hover) +``` + +## Result: + +``` +[42, 42] +[42, 1] +[1, 2] +[2, 3] +[3, 42] +[42, 42] +``` + +""" + + +def convolved(iterable, kernel_size=1, stride=1, padding=0, default_value=None): + """Iterable to get every convolution window per loop iteration. + + For example: + `convolved([1, 2, 3, 4], kernel_size=2)` + will produce the following result: + `[[1, 2], [2, 3], [3, 4]]`. + `convolved([1, 2, 3], kernel_size=2, stride=1, padding=2, default_value=42)` + will produce the following result: + `[[42, 42], [42, 1], [1, 2], [2, 3], [3, 42], [42, 42]]` + + Arguments: + iterable: An object to iterate on. It should support slice indexing if `padding == 0`. + kernel_size: The number of items yielded at every iteration. + stride: The step size between each iteration. + padding: Padding must be an integer or a string with value `SAME` or `VALID`. If it is an integer, it represents + how many values we add with `default_value` on the borders. If it is a string, `SAME` means that the + convolution will add some padding according to the kernel_size, and `VALID` is the same as + specifying `padding=0`. + default_value: Default fill value for padding and values outside iteration range. + + For more information, refer to: + - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py + - https://github.com/guillaume-chevalier/python-conv-lib + - MIT License, Copyright (c) 2018 Guillaume Chevalier + """ + # Input validation and error messages + if not hasattr(iterable, '__iter__'): + raise ValueError( + "Can't iterate on object.".format( + iterable)) + if stride < 1: + raise ValueError( + "Stride must be of at least one. Got `stride={}`.".format( + stride)) + if not (padding in ['SAME', 'VALID'] or type(padding) in [int]): + raise ValueError( + "Padding must be an integer or a string with value `SAME` or `VALID`.") + if not isinstance(padding, str): + if padding < 0: + raise ValueError( + "Padding must be of at least zero. Got `padding={}`.".format( + padding)) + else: + if padding == 'SAME': + padding = kernel_size // 2 + elif padding == 'VALID': + padding = 0 + if not type(iterable) == list: + iterable = list(iterable) + + # Add padding to iterable + if padding > 0: + pad = [default_value] * padding + iterable = pad + list(iterable) + pad + + # Fill missing value to the right + remainder = (kernel_size - len(iterable)) % stride + extra_pad = [default_value] * remainder + iterable = iterable + extra_pad + + i = 0 + while True: + if i > len(iterable) - kernel_size: + break + yield iterable[i:i + kernel_size] + i += stride + +def convolved_1d(iterable, kernel_size=1, stride=1, padding=0, default_value=None): + """1D Iterable to get every convolution window per loop iteration. + + For more information, refer to: + - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py + - https://github.com/guillaume-chevalier/python-conv-lib + - MIT License, Copyright (c) 2018 Guillaume Chevalier + """ + return convolved(iterable, kernel_size, stride, padding, default_value) + + +def convolved_2d(iterable, kernel_size=1, stride=1, padding=0, default_value=None): + """2D Iterable to get every convolution window per loop iteration. + + For more information, refer to: + - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py + - https://github.com/guillaume-chevalier/python-conv-lib + - MIT License, Copyright (c) 2018 Guillaume Chevalier + """ + kernel_size = dimensionize(kernel_size, nd=2) + stride = dimensionize(stride, nd=2) + padding = dimensionize(padding, nd=2) + + for row_packet in convolved(iterable, kernel_size[0], stride[0], padding[0], default_value): + transposed_inner = [] + for col in tuple(row_packet): + transposed_inner.append(list( + convolved(col, kernel_size[1], stride[1], padding[1], default_value) + )) + + if len(transposed_inner) > 0: + for col_i in range(len(transposed_inner[0])): + yield tuple(row_j[col_i] for row_j in transposed_inner) + + +def dimensionize(maybe_a_list, nd=2): + """Convert integers to a list of integers to fit the number of dimensions if + the argument is not already a list. + + For example: + `dimensionize(3, nd=2)` + will produce the following result: + `(3, 3)`. + `dimensionize([3, 1], nd=2)` + will produce the following result: + `[3, 1]`. + + For more information, refer to: + - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py + - https://github.com/guillaume-chevalier/python-conv-lib + - MIT License, Copyright (c) 2018 Guillaume Chevalier + """ + if not hasattr(maybe_a_list, '__iter__'): + # Argument is probably an integer so we map it to a list of size `nd`. + now_a_list = [maybe_a_list] * nd + return now_a_list + else: + # Argument is probably an `nd`-sized list. + return maybe_a_list diff --git a/tests/test_iterables.py b/tests/test_iterables.py new file mode 100644 index 000000000..4e23d850e --- /dev/null +++ b/tests/test_iterables.py @@ -0,0 +1,161 @@ +from algorithms.iterables import ( + convolved_1d, convolved_2d +) + +import itertools +import unittest + + +class TestConvolved1D(unittest.TestCase): + """Tests copied from: + - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/tests/test_convolved_1d.py + - MIT License, Copyright (c) 2018 Guillaume Chevalier + """ + + def test_trivial_loop(self): + expected = tuple(range(7)) + result = [] + + for kernel_hover in convolved_1d(expected, kernel_size=1, padding=0, stride=1): + result.append(*kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_for_with_stride_two(self): + expected = tuple(range(0, 7, 2)) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=1, padding=0, stride=2): + result.append(*kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_for_with_padding_one(self): + expected = tuple([42] + list(range(0, 7)) + [42]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=1, padding=1, stride=1, default_value=42): + result.append(*kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_two(self): + expected = tuple([a, b] for a, b in zip(list(range(0, 6)), list(range(1, 7)))) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=0, stride=1): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_two_and_stride_two(self): + expected = ([0, 1], [2, 3], [4, 5], [6, None]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=0, stride=2): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_two_and_stride_two_and_padding_two(self): + expected = ([None, None], [0, 1], [2, 3], [4, 5], [6, None], [None, None]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=2, stride=2): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_two_and_stride_two_and_padding_three(self): + expected = ([None, None], [None, 0], [1, 2], [3, 4], [5, 6], [None, None], [None, None]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=3, stride=2): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_three_and_stride_two_and_padding_two(self): + expected = ([None, None, 0], [0, 1, 2], [2, 3, 4], [4, 5, 6], [6, None, None]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=3, padding=2, stride=2): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_two_and_stride_three_and_padding_two(self): + expected = ([None, None], [1, 2], [4, 5], [None, None]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=2, stride=3): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_seven_kernel_of_three_and_stride_three_and_padding_three(self): + expected = ([None, None, None], [0, 1, 2], [3, 4, 5], [6, None, None], [None, None, None]) + result = [] + + for kernel_hover in convolved_1d(list(range(7)), kernel_size=3, padding=3, stride=3): + result.append(kernel_hover) + result = tuple(result) + + self.assertEqual(expected, result) + + +class TestConvolved2D(unittest.TestCase): + """Tests copied from: + - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/tests/test_convolved_1d.py + - MIT License, Copyright (c) 2018 Guillaume Chevalier + """ + + def test_trivial_1x1_loop(self): + base = tuple(tuple(range(i ** 2, 7 + i ** 2)) for i in range(7)) + expected = tuple(([i],) for i in itertools.chain(*base)) + result = [] + + for kernel_hover in convolved_2d(base, kernel_size=1, padding=0, stride=1): + result.append(tuple(kernel_hover)) + result = tuple(result) + + self.assertEqual(expected, result) + + def test_simple_2x2_loop_on_3x2(self): + base = [ + [1, 2], + [3, 4], + [5, 6] + ] + expected = ( + ( + [1, 2], + [3, 4] + ), ( + [3, 4], + [5, 6] + ) + ) + result = [] + + for kernel_hover in convolved_2d(base, kernel_size=2, padding=0, stride=1): + result.append(tuple(kernel_hover)) + result = tuple(result) + + print(result) + print(expected) + + self.assertEqual(expected, result) + + +if __name__ == "__main__": + unittest.main() diff --git a/tree.md b/tree.md index adaa28165..8fe302f19 100644 --- a/tree.md +++ b/tree.md @@ -107,6 +107,9 @@ algorithms │   ├── skyline.py │   └── sliding_window_max.py ├── __init__.py +├── iterables +│   ├── __init__.py +│   └── convolved.py ├── linkedlist │   ├── add_two_numbers.py │   ├── copy_random_pointer.py @@ -296,5 +299,5 @@ algorithms └── union-find └── count_islands.py -27 directories, 267 files +28 directories, 269 files ``` From a883c959c5c0d364c136fbf54cf54db89054ec33 Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Thu, 28 Mar 2019 18:56:44 +0800 Subject: [PATCH 145/302] fix bugs, add descriptions, and add tests (#489) * fix: test_heap, tree/traversal/__init__ * fix a error in longest_non_repeat.py * fix bugs, add notes, and add tests * fix bugs, add descriptions, and add tests * fix bugs, add descriptions, and add tests * fix bugs, add descriptions, and add tests --- algorithms/bfs/maze_search.py | 15 +++++++ algorithms/bfs/word_ladder.py | 29 +------------ algorithms/bit/__init__.py | 1 + algorithms/bit/count_flips_to_convert.py | 2 +- algorithms/bit/count_ones.py | 8 ++-- algorithms/bit/find_missing_number.py | 4 ++ algorithms/bit/insert_bit.py | 4 +- algorithms/dfs/__init__.py | 5 +++ algorithms/dfs/all_factors.py | 16 ------- algorithms/dfs/count_islands.py | 10 ++--- algorithms/dfs/sudoku_solver.py | 15 ------- algorithms/dfs/walls_and_gates.py | 22 ++++++++-- tests/test_bfs.py | 27 +++++++++++- tests/test_bit.py | 14 ++++++ tests/test_dfs.py | 55 ++++++++++++++++++++++++ 15 files changed, 151 insertions(+), 76 deletions(-) create mode 100644 algorithms/dfs/__init__.py create mode 100644 tests/test_dfs.py diff --git a/algorithms/bfs/maze_search.py b/algorithms/bfs/maze_search.py index efa65c357..436b3ef59 100644 --- a/algorithms/bfs/maze_search.py +++ b/algorithms/bfs/maze_search.py @@ -7,6 +7,21 @@ only step on the columns whose value is 1 if there is no path, it returns -1 + +Ex 1) +If grid is +[[1,0,1,1,1,1], + [1,0,1,0,1,0], + [1,0,1,0,1,1], + [1,1,1,0,1,1]], +the answer is: 14 + +Ex 2) +If grid is +[[1,0,0], + [0,1,1], + [0,1,1]], +the answer is: -1 ''' def maze_search(grid): diff --git a/algorithms/bfs/word_ladder.py b/algorithms/bfs/word_ladder.py index 2fdbf294e..6767571eb 100644 --- a/algorithms/bfs/word_ladder.py +++ b/algorithms/bfs/word_ladder.py @@ -13,13 +13,12 @@ word_list = ["hot","dot","dog","lot","log"] As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5. -. + Note: Return -1 if there is no such transformation sequence. All words have the same length. All words contain only lowercase alphabetic characters. """ -import unittest def ladder_length(begin_word, end_word, word_list): @@ -71,29 +70,3 @@ def word_range(word): for c in [chr(x) for x in range(ord('a'), ord('z') + 1)]: if c != temp: yield word[:ind] + c + word[ind + 1:] - - -class TestSuite(unittest.TestCase): - - def test_ladder_length(self): - - # hit -> hot -> dot -> dog -> cog - self.assertEqual(5, ladder_length('hit', 'cog', ["hot", "dot", "dog", "lot", "log"])) - - # pick -> sick -> sink -> sank -> tank == 5 - self.assertEqual(5, ladder_length('pick', 'tank', - ['tock', 'tick', 'sank', 'sink', 'sick'])) - - # live -> life == 1, no matter what is the word_list. - self.assertEqual(1, ladder_length('live', 'life', ['hoho', 'luck'])) - - # 0 length from ate -> ate - self.assertEqual(0, ladder_length('ate', 'ate', [])) - - # not possible to reach ! - self.assertEqual(-1, ladder_length('rahul', 'coder', ['blahh', 'blhah'])) - - -if __name__ == '__main__': - - unittest.main() diff --git a/algorithms/bit/__init__.py b/algorithms/bit/__init__.py index 617f5006f..fa31d7ed8 100644 --- a/algorithms/bit/__init__.py +++ b/algorithms/bit/__init__.py @@ -16,3 +16,4 @@ from .count_flips_to_convert import * from .flip_bit_longest_sequence import * from .binary_gap import * +from .bytes_int_conversion import * \ No newline at end of file diff --git a/algorithms/bit/count_flips_to_convert.py b/algorithms/bit/count_flips_to_convert.py index 6ba1d116d..375e68f21 100644 --- a/algorithms/bit/count_flips_to_convert.py +++ b/algorithms/bit/count_flips_to_convert.py @@ -1,5 +1,5 @@ """ -Write a function to determine the number of bits you would need to +Write a function to determine the minimal number of bits you would need to flip to convert integer A to integer B. For example: Input: 29 (or: 11101), 15 (or: 01111) diff --git a/algorithms/bit/count_ones.py b/algorithms/bit/count_ones.py index 700efe9e2..e96161e72 100644 --- a/algorithms/bit/count_ones.py +++ b/algorithms/bit/count_ones.py @@ -1,9 +1,9 @@ """ Write a function that takes an unsigned integer and -returns the number of ’1' bits it has +returns the number of '1' bits it has (also known as the Hamming weight). -For example, the 32-bit integer ’11' has binary +For example, the 32-bit integer '1' has binary representation 00000000000000000000000000001011, so the function should return 3. @@ -15,7 +15,7 @@ Number of loops is equal to the number of 1s in the binary representation.""" def count_ones_recur(n): - """Using Brian Kernighan’s Algorithm. (Recursive Approach)""" + """Using Brian Kernighan's Algorithm. (Recursive Approach)""" if not n: return 0 @@ -23,7 +23,7 @@ def count_ones_recur(n): def count_ones_iter(n): - """Using Brian Kernighan’s Algorithm. (Iterative Approach)""" + """Using Brian Kernighan's Algorithm. (Iterative Approach)""" count = 0 while n: diff --git a/algorithms/bit/find_missing_number.py b/algorithms/bit/find_missing_number.py index 9aedc508b..2e47df4d1 100644 --- a/algorithms/bit/find_missing_number.py +++ b/algorithms/bit/find_missing_number.py @@ -3,6 +3,10 @@ in range [0..n] in O(n) time and space. The difference between consecutive integers cannot be more than 1. If the sequence is already complete, the next integer in the sequence will be returned. + + For example: + Input: nums = [4, 1, 3, 0, 6, 5, 2] + Output: 7 """ def find_missing_number(nums): diff --git a/algorithms/bit/insert_bit.py b/algorithms/bit/insert_bit.py index f799489c8..a86e042f4 100644 --- a/algorithms/bit/insert_bit.py +++ b/algorithms/bit/insert_bit.py @@ -6,7 +6,7 @@ Input: num = 10101 (21) insert_one_bit(num, 1, 2): 101101 (45) -insert_one_bit(num, 0 ,2): 101001 (41) +insert_one_bit(num, 0, 2): 101001 (41) insert_one_bit(num, 1, 5): 110101 (53) insert_one_bit(num, 1, 0): 101011 (43) @@ -25,7 +25,7 @@ Algorithm: 1. Create a mask having bit from i to the most significant bit, and append the new bit at 0 position 2. Keep the bit from 0 position to i position ( like 000...001111) -3) Merge mask and num +3. Merge mask and num """ def insert_one_bit(num, bit, i): # Create mask diff --git a/algorithms/dfs/__init__.py b/algorithms/dfs/__init__.py new file mode 100644 index 000000000..03af1291e --- /dev/null +++ b/algorithms/dfs/__init__.py @@ -0,0 +1,5 @@ +from .all_factors import * +from .count_islands import * +from .pacific_atlantic import * +from .sudoku_solver import * +from .walls_and_gates import * diff --git a/algorithms/dfs/all_factors.py b/algorithms/dfs/all_factors.py index 6c692f30b..13438d41f 100644 --- a/algorithms/dfs/all_factors.py +++ b/algorithms/dfs/all_factors.py @@ -27,8 +27,6 @@ [2, 2, 2, 4], [2, 2, 2, 2, 2], """ -import unittest - def get_factors(n): """[summary] @@ -111,17 +109,3 @@ def get_factors_iterative2(n): n //= x else: x += 1 - -class TestAllFactors(unittest.TestCase): - def test_get_factors(self): - self.assertEqual([[2, 16], [2, 2, 8], [2, 2, 2, 4], [2, 2, 2, 2, 2], [2, 4, 4], [4, 8]], - get_factors(32)) - def test_get_factors_iterative1(self): - self.assertEqual([[2, 16], [4, 8], [2, 2, 8], [2, 4, 4], [2, 2, 2, 4], [2, 2, 2, 2, 2]], - get_factors_iterative1(32)) - def test_get_factors_iterative2(self): - self.assertEqual([[2, 2, 2, 2, 2], [2, 2, 2, 4], [2, 2, 8], [2, 4, 4], [2, 16], [4, 8]], - get_factors_iterative2(32)) - -if __name__ == "__main__": - unittest.main() diff --git a/algorithms/dfs/count_islands.py b/algorithms/dfs/count_islands.py index 60f6802d2..21bcee85a 100644 --- a/algorithms/dfs/count_islands.py +++ b/algorithms/dfs/count_islands.py @@ -24,20 +24,20 @@ def num_islands(grid): count = 0 - for i, row in enumerate(grid): + for i in range(len(grid)): for j, col in enumerate(grid[i]): - if col == '1': + if col == 1: dfs(grid, i, j) count += 1 return count def dfs(grid, i, j): - if (i < 0 or i >= len(grid)) or (j < 0 or len(grid[0])): + if (i < 0 or i >= len(grid)) or (j < 0 or j >= len(grid[0])): return - if grid[i][j] != '1': + if grid[i][j] != 1: return - grid[i][j] = '0' + grid[i][j] = 0 dfs(grid, i+1, j) dfs(grid, i-1, j) dfs(grid, i, j+1) diff --git a/algorithms/dfs/sudoku_solver.py b/algorithms/dfs/sudoku_solver.py index 387cdcaea..e7ba9aa02 100644 --- a/algorithms/dfs/sudoku_solver.py +++ b/algorithms/dfs/sudoku_solver.py @@ -20,9 +20,6 @@ fine for now. (it would look less lengthy if we are allowed to use numpy array for the board lol). """ - -import unittest - class Sudoku: def __init__ (self, board, row, col): self.board = board @@ -96,15 +93,3 @@ def __str__(self): resp += " {0} ".format(self.board[i][j]) resp += "\n" return resp - - -class TestSudoku(unittest.TestCase): - def test_sudoku_solver(self): - board = [["5","3","."], ["6",".", "."],[".","9","8"]] - test_obj = Sudoku(board, 3, 3) - test_obj.solve() - self.assertEqual([['5', '3', '1'], ['6', '1', '2'], ['1', '9', '8']],test_obj.board) - - -if __name__ == "__main__": - unittest.main() diff --git a/algorithms/dfs/walls_and_gates.py b/algorithms/dfs/walls_and_gates.py index 7d10b4d6e..0369203d9 100644 --- a/algorithms/dfs/walls_and_gates.py +++ b/algorithms/dfs/walls_and_gates.py @@ -1,7 +1,23 @@ +""" +You are given a m x n 2D grid initialized with these three possible values: + -1: A wall or an obstacle. + 0: A gate. + INF: Infinity means an empty room. We use the value 2^31 - 1 = 2147483647 to represent INF + as you may assume that the distance to a gate is less than 2147483647. +Fill the empty room with distance to its nearest gate. +If it is impossible to reach a gate, it should be filled with INF. - -# fill the empty room with distance to its nearest gate - +For example, given the 2D grid: + INF -1 0 INF + INF INF INF -1 + INF -1 INF -1 + 0 -1 INF INF +After running your function, the 2D grid should be: + 3 -1 0 1 + 2 2 1 -1 + 1 -1 2 -1 + 0 -1 3 4 +""" def walls_and_gates(rooms): for i in range(len(rooms)): diff --git a/tests/test_bfs.py b/tests/test_bfs.py index 129d6d067..62c179bbc 100644 --- a/tests/test_bfs.py +++ b/tests/test_bfs.py @@ -1,11 +1,12 @@ from algorithms.bfs import ( maze_search, shortest_distance_from_all_buildings, - word_ladder + ladder_length ) import unittest + class TestMazeSearch(unittest.TestCase): def test_maze_search(self): @@ -13,6 +14,28 @@ def test_maze_search(self): self.assertEqual(14, maze_search(grid_1)) grid_2 = [[1,0,0],[0,1,1],[0,1,1]] self.assertEqual(-1, maze_search(grid_2)) - + + +class TestWordLadder(unittest.TestCase): + + def test_ladder_length(self): + + # hit -> hot -> dot -> dog -> cog + self.assertEqual(5, ladder_length('hit', 'cog', ["hot", "dot", "dog", "lot", "log"])) + + # pick -> sick -> sink -> sank -> tank == 5 + self.assertEqual(5, ladder_length('pick', 'tank', + ['tock', 'tick', 'sank', 'sink', 'sick'])) + + # live -> life == 1, no matter what is the word_list. + self.assertEqual(1, ladder_length('live', 'life', ['hoho', 'luck'])) + + # 0 length from ate -> ate + self.assertEqual(0, ladder_length('ate', 'ate', [])) + + # not possible to reach ! + self.assertEqual(-1, ladder_length('rahul', 'coder', ['blahh', 'blhah'])) + + if __name__ == "__main__": unittest.main() diff --git a/tests/test_bit.py b/tests/test_bit.py index acfb4b035..23e9d94f5 100644 --- a/tests/test_bit.py +++ b/tests/test_bit.py @@ -11,6 +11,8 @@ single_number3, subsets, get_bit, set_bit, clear_bit, update_bit, + int_to_bytes_big_endian, int_to_bytes_little_endian, + bytes_big_endian_to_int, bytes_little_endian_to_int, swap_pair, find_difference, has_alternative_bit, has_alternative_bit_fast, @@ -183,6 +185,18 @@ def test_update_bit(self): # 22 = 10110 --> after update bit at 2nd position with value 0: 20 = 10010 self.assertEqual(18, update_bit(22, 2, 0)) + def test_int_to_bytes_big_endian(self): + self.assertEqual(b'\x11', int_to_bytes_big_endian(17)) + + def test_int_to_bytes_little_endian(self): + self.assertEqual(b'\x11', int_to_bytes_little_endian(17)) + + def test_bytes_big_endian_to_int(self): + self.assertEqual(17, bytes_big_endian_to_int(b'\x11')) + + def test_bytes_little_endian_to_int(self): + self.assertEqual(17, bytes_little_endian_to_int(b'\x11')) + def test_swap_pair(self): # 22: 10110 --> 41: 101001 self.assertEqual(41, swap_pair(22)) diff --git a/tests/test_dfs.py b/tests/test_dfs.py new file mode 100644 index 000000000..ed1c3f263 --- /dev/null +++ b/tests/test_dfs.py @@ -0,0 +1,55 @@ +from algorithms.dfs import ( + get_factors, get_factors_iterative1, get_factors_iterative2, + num_islands, + pacific_atlantic, + Sudoku, + walls_and_gates +) + +import unittest + + +class TestAllFactors(unittest.TestCase): + def test_get_factors(self): + self.assertEqual([[2, 16], [2, 2, 8], [2, 2, 2, 4], [2, 2, 2, 2, 2], [2, 4, 4], [4, 8]], + get_factors(32)) + def test_get_factors_iterative1(self): + self.assertEqual([[2, 16], [4, 8], [2, 2, 8], [2, 4, 4], [2, 2, 2, 4], [2, 2, 2, 2, 2]], + get_factors_iterative1(32)) + def test_get_factors_iterative2(self): + self.assertEqual([[2, 2, 2, 2, 2], [2, 2, 2, 4], [2, 2, 8], [2, 4, 4], [2, 16], [4, 8]], + get_factors_iterative2(32)) + + +class TestCountIslands(unittest.TestCase): + def test_num_islands(self): + self.assertEqual(1, num_islands([[1, 1, 1, 1, 0], [1, 1, 0, 1, 0], [1, 1, 0, 0, 0], [0, 0, 0, 0, 0]])) + self.assertEqual(3, num_islands([[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]])) + + +class TestPacificAtlantic(unittest.TestCase): + def test_pacific_atlantic(self): + self.assertEqual([[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]], + pacific_atlantic([[1, 2, 2, 3, 5], [3, 2, 3, 4, 4], [2, 4, 5, 3, 1], [6, 7, 1, 4, 5], [5, 1, 1, 2, 4]])) + + +class TestSudoku(unittest.TestCase): + def test_sudoku_solver(self): + board = [["5","3","."], ["6",".", "."],[".","9","8"]] + test_obj = Sudoku(board, 3, 3) + test_obj.solve() + self.assertEqual([['5', '3', '1'], ['6', '1', '2'], ['1', '9', '8']],test_obj.board) + + +class TestWallsAndGates(unittest.TestCase): + def test_walls_and_gates(self): + rooms = [[float("inf"), -1, 0, float("inf")], + [float("inf"), float("inf"), float("inf"), -1], + [float("inf"), -1, float("inf"), -1], + [0, -1, float("inf"), float("inf")]] + walls_and_gates(rooms) + self.assertEqual([[3, -1, 0, 1], [2, 2, 1, -1], [1, -1, 2, -1], [0, -1, 3, 4]], rooms) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 33ed167a81021c403225f0a2784b295dd5b1b8c0 Mon Sep 17 00:00:00 2001 From: Liang Jiakun <34836930+JKLiang9714@users.noreply.github.com> Date: Sat, 30 Mar 2019 07:49:40 +0800 Subject: [PATCH 146/302] fix bugs, add descriptions, and add tests (#491) * fix: test_heap, tree/traversal/__init__ * fix a error in longest_non_repeat.py * fix bugs, add notes, and add tests * fix bugs, add descriptions, and add tests * fix bugs, add descriptions, and add tests * fix bugs, add descriptions, and add tests * fix bugs, add descriptions, and add tests --- algorithms/bit/count_ones.py | 2 +- algorithms/dp/__init__.py | 19 ++++++ algorithms/dp/climbing_stairs.py | 2 +- algorithms/dp/coin_change.py | 13 +--- algorithms/dp/combination_sum.py | 6 -- algorithms/dp/egg_drop.py | 29 ++++++-- algorithms/dp/fib.py | 5 +- algorithms/dp/house_robber.py | 4 -- algorithms/dp/job_scheduling.py | 4 +- algorithms/dp/knapsack.py | 6 -- algorithms/dp/longest_increasing.py | 17 +++-- tests/test_dp.py | 100 ++++++++++++++++++++++++++-- 12 files changed, 157 insertions(+), 50 deletions(-) diff --git a/algorithms/bit/count_ones.py b/algorithms/bit/count_ones.py index e96161e72..ac718f336 100644 --- a/algorithms/bit/count_ones.py +++ b/algorithms/bit/count_ones.py @@ -3,7 +3,7 @@ returns the number of '1' bits it has (also known as the Hamming weight). -For example, the 32-bit integer '1' has binary +For example, the 32-bit integer '11' has binary representation 00000000000000000000000000001011, so the function should return 3. diff --git a/algorithms/dp/__init__.py b/algorithms/dp/__init__.py index 174f524bf..892540972 100644 --- a/algorithms/dp/__init__.py +++ b/algorithms/dp/__init__.py @@ -1 +1,20 @@ +from .buy_sell_stock import * +from .climbing_stairs import * +from .coin_change import * +from .combination_sum import * from .edit_distance import * +from .egg_drop import * +from .fib import * +from .hosoya_triangle import * +from .house_robber import * +from .job_scheduling import * +from .knapsack import * +from .longest_increasing import * +from .matrix_chain_order import * +from .max_product_subarray import * +from .max_subarray import * +from .min_cost_path import * +from .num_decodings import * +from .regex_matching import * +from .rod_cut import * +from .word_break import * diff --git a/algorithms/dp/climbing_stairs.py b/algorithms/dp/climbing_stairs.py index 6f5f3b697..0c02efe51 100644 --- a/algorithms/dp/climbing_stairs.py +++ b/algorithms/dp/climbing_stairs.py @@ -17,7 +17,7 @@ def climb_stairs(n): :rtype: int """ arr = [1, 1] - for i in range(2, n+1): + for _ in range(1, n): arr.append(arr[-1] + arr[-2]) return arr[-1] diff --git a/algorithms/dp/coin_change.py b/algorithms/dp/coin_change.py index dce9bb57a..db1479633 100644 --- a/algorithms/dp/coin_change.py +++ b/algorithms/dp/coin_change.py @@ -2,7 +2,7 @@ Problem Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued //coins, how many ways can we make the change? -The order of coins doesn’t matter. +The order of coins doesn't matter. For example, for N = 4 and S = [1, 2, 3], there are four solutions: [1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3]. So output should be 4. @@ -35,14 +35,3 @@ def count(s, n): table[i][j] = x + y return table[n][m-1] - - -if __name__ == '__main__': - - coins = [1, 2, 3] - n = 4 - assert count(coins, n) == 4 - - coins = [2, 5, 3, 6] - n = 10 - assert count(coins, n) == 5 diff --git a/algorithms/dp/combination_sum.py b/algorithms/dp/combination_sum.py index 67bc6aff7..57587ff91 100644 --- a/algorithms/dp/combination_sum.py +++ b/algorithms/dp/combination_sum.py @@ -58,9 +58,3 @@ def combination_sum_bottom_up(nums, target): if i - nums[j] >= 0: comb[i] += comb[i - nums[j]] return comb[target] - - -combination_sum_topdown([1, 2, 3], 4) -print(dp[4]) - -print(combination_sum_bottom_up([1, 2, 3], 4)) diff --git a/algorithms/dp/egg_drop.py b/algorithms/dp/egg_drop.py index c087982c5..d07bee872 100644 --- a/algorithms/dp/egg_drop.py +++ b/algorithms/dp/egg_drop.py @@ -1,14 +1,35 @@ +""" +You are given K eggs, and you have access to a building with N floors +from 1 to N. Each egg is identical in function, and if an egg breaks, +you cannot drop it again. You know that there exists a floor F with +0 <= F <= N such that any egg dropped at a floor higher than F will +break, and any egg dropped at or below floor F will not break. +Each move, you may take an egg (if you have an unbroken one) and drop +it from any floor X (with 1 <= X <= N). Your goal is to know with +certainty what the value of F is. What is the minimum number of moves +that you need to know with certainty what F is, regardless of the +initial value of F? + +Example: +Input: K = 1, N = 2 +Output: 2 +Explanation: +Drop the egg from floor 1. If it breaks, we know with certainty that F = 0. +Otherwise, drop the egg from floor 2. If it breaks, we know with +certainty that F = 1. +If it didn't break, then we know with certainty F = 2. +Hence, we needed 2 moves in the worst case to know what F is with certainty. +""" + # A Dynamic Programming based Python Program for the Egg Dropping Puzzle INT_MAX = 32767 - -# Function to get minimum number of trials needed in worst -# case with n eggs and k floors + def egg_drop(n, k): # A 2D table where entery eggFloor[i][j] will represent minimum # number of trials needed for i eggs and j floors. egg_floor = [[0 for x in range(k+1)] for x in range(n+1)] - # We need one trial for one floor and0 trials for 0 floors + # We need one trial for one floor and 0 trials for 0 floors for i in range(1, n+1): egg_floor[i][1] = 1 egg_floor[i][0] = 0 diff --git a/algorithms/dp/fib.py b/algorithms/dp/fib.py index 765ee2f34..6762e90db 100644 --- a/algorithms/dp/fib.py +++ b/algorithms/dp/fib.py @@ -63,11 +63,10 @@ def fib_iter(n): sum = 0 if n <= 1: return n - for i in range(n-1): + for _ in range(n-1): sum = fib_1 + fib_2 fib_1 = fib_2 fib_2 = sum return sum -# => 354224848179261915075 -# print(fib_iter(100)) +# print(fib_iter(100)) # => 354224848179261915075 diff --git a/algorithms/dp/house_robber.py b/algorithms/dp/house_robber.py index 88baaa9c4..a2a8a6d92 100644 --- a/algorithms/dp/house_robber.py +++ b/algorithms/dp/house_robber.py @@ -19,7 +19,3 @@ def house_robber(houses): now = max(last + house, now) last = tmp return now - -houses = [1, 2, 16, 3, 15, 3, 12, 1] - -print(house_robber(houses)) diff --git a/algorithms/dp/job_scheduling.py b/algorithms/dp/job_scheduling.py index 7c7236820..eaf98ec44 100644 --- a/algorithms/dp/job_scheduling.py +++ b/algorithms/dp/job_scheduling.py @@ -45,7 +45,7 @@ def schedule(job): n = len(job) table = [0 for _ in range(n)] - table[0] = job[0].profit; + table[0] = job[0].profit # Fill entries in table[] using recursive property for i in range(1, n): @@ -54,7 +54,7 @@ def schedule(job): incl_prof = job[i].profit l = binary_search(job, i) if (l != -1): - incl_prof += table[l]; + incl_prof += table[l] # Store maximum of including and excluding table[i] = max(incl_prof, table[i - 1]) diff --git a/algorithms/dp/knapsack.py b/algorithms/dp/knapsack.py index e906ae0b7..65f7d8941 100644 --- a/algorithms/dp/knapsack.py +++ b/algorithms/dp/knapsack.py @@ -30,9 +30,3 @@ def get_maximum_value(items, capacity): dp[current_weight] + item.value) dp = dp_tmp return max(dp) - - -print(get_maximum_value([Item(60, 10), Item(100, 20), Item(120, 30)], - 50)) -print(get_maximum_value([Item(60, 5), Item(50, 3), Item(70, 4), Item(30, 2)], - 5)) diff --git a/algorithms/dp/longest_increasing.py b/algorithms/dp/longest_increasing.py index 5f6eb8369..71971376b 100644 --- a/algorithms/dp/longest_increasing.py +++ b/algorithms/dp/longest_increasing.py @@ -1,4 +1,14 @@ +""" +Given an unsorted array of integers, find the length of longest increasing subsequence. +Example: + +Input: [10,9,2,5,3,7,101,18] +Output: 4 +Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. + +The time complexity is O(n^2). +""" def longest_increasing_subsequence(sequence): """ @@ -14,10 +24,3 @@ def longest_increasing_subsequence(sequence): counts[i] = max(counts[i], counts[j] + 1) print(counts) return max(counts) - - -sequence = [1, 101, 10, 2, 3, 100, 4, 6, 2] -print("sequence: ", sequence) -print("output: ", longest_increasing_subsequence(sequence)) -print("answer: ", 5) - diff --git a/tests/test_dp.py b/tests/test_dp.py index 2edaadfc3..08f6bd0a9 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -1,17 +1,83 @@ from algorithms.dp import ( + max_profit_naive, max_profit_optimized, + climb_stairs, climb_stairs_optimized, + count, + combination_sum_topdown, combination_sum_bottom_up, edit_distance, - hosoya_triangle + egg_drop, + fib_recursive, fib_list, fib_iter, + hosoya_testing, + house_robber, + Job, schedule, + Item, get_maximum_value, + longest_increasing_subsequence ) import unittest +class TestBuySellStock(unittest.TestCase): + def test_max_profit_naive(self): + self.assertEqual(max_profit_naive([7, 1, 5, 3, 6, 4]), 5) + self.assertEqual(max_profit_naive([7, 6, 4, 3, 1]), 0) + + def test_max_profit_optimized(self): + self.assertEqual(max_profit_optimized([7, 1, 5, 3, 6, 4]), 5) + self.assertEqual(max_profit_optimized([7, 6, 4, 3, 1]), 0) + + +class TestClimbingStairs(unittest.TestCase): + def test_climb_stairs(self): + self.assertEqual(climb_stairs(2), 2) + self.assertEqual(climb_stairs(10), 89) + + def test_climb_stairs_optimized(self): + self.assertEqual(climb_stairs_optimized(2), 2) + self.assertEqual(climb_stairs_optimized(10), 89) + + +class TestCoinChange(unittest.TestCase): + def test_count(self): + self.assertEqual(count([1, 2, 3], 4), 4) + self.assertEqual(count([2, 5, 3, 6], 10), 5) + + +class TestCombinationSum(unittest.TestCase): + def test_combination_sum_topdown(self): + self.assertEqual(combination_sum_topdown([1, 2, 3], 4), 7) + + def test_combination_sum_bottom_up(self): + self.assertEqual(combination_sum_bottom_up([1, 2, 3], 4), 7) + + class TestEditDistance(unittest.TestCase): def test_edit_distance(self): self.assertEqual(edit_distance('food', 'money'), 4) self.assertEqual(edit_distance('horse', 'ros'), 3) + +class TestEggDrop(unittest.TestCase): + def test_egg_drop(self): + self.assertEqual(egg_drop(1, 2), 2) + self.assertEqual(egg_drop(2, 6), 3) + self.assertEqual(egg_drop(3, 14), 4) + + +class TestFib(unittest.TestCase): + def test_fib_recursive(self): + self.assertEqual(fib_recursive(10), 55) + self.assertEqual(fib_recursive(30), 832040) + + def test_fib_list(self): + self.assertEqual(fib_list(10), 55) + self.assertEqual(fib_list(30), 832040) + + def test_fib_iter(self): + self.assertEqual(fib_iter(10), 55) + self.assertEqual(fib_iter(30), 832040) + + class TestHosoyaTriangle(unittest.TestCase): """[summary] Test for the file hosoya_triangle @@ -21,14 +87,14 @@ class TestHosoyaTriangle(unittest.TestCase): """ def test_hosoya(self): - self.assertEqual([1], hosoya_triangle.hosoya_testing(1)) + self.assertEqual([1], hosoya_testing(1)) self.assertEqual([1, 1, 1, 2, 1, 2, 3, 2, 2, 3, 5, 3, 4, 3, 5, 8, 5, 6, 6, 5, 8], - hosoya_triangle.hosoya_testing(6)) + hosoya_testing(6)) self.assertEqual([1, 1, 1, 2, 1, 2, @@ -39,7 +105,33 @@ def test_hosoya(self): 21, 13, 16, 15, 15, 16, 13, 21, 34, 21, 26, 24, 25, 24, 26, 21, 34, 55, 34, 42, 39, 40, 40, 39, 42, 34, 55], - hosoya_triangle.hosoya_testing(10)) + hosoya_testing(10)) + + +class TestHouseRobber(unittest.TestCase): + def test_house_robber(self): + self.assertEqual(44, house_robber([1, 2, 16, 3, 15, 3, 12, 1])) + + +class TestJobScheduling(unittest.TestCase): + def test_job_scheduling(self): + job1, job2 = Job(1, 3, 2), Job(2, 3, 4) + self.assertEqual(4, schedule([job1, job2])) + + +class TestKnapsack(unittest.TestCase): + def test_get_maximum_value(self): + item1, item2, item3 = Item(60, 10), Item(100, 20), Item(120, 30) + self.assertEqual(220, get_maximum_value([item1, item2, item3], 50)) + + item1, item2, item3, item4 = Item(60, 5), Item(50, 3), Item(70, 4), Item(30, 2) + self.assertEqual(80, get_maximum_value([item1, item2, item3, item4], 5)) + + +class TestLongestIncreasingSubsequence(unittest.TestCase): + def test_longest_increasing_subsequence(self): + sequence = [1, 101, 10, 2, 3, 100, 4, 6, 2] + self.assertEqual(5, longest_increasing_subsequence(sequence)) if __name__ == '__main__': From bc850daaae8f330167191ec6bfaa53318009454a Mon Sep 17 00:00:00 2001 From: keon Date: Sat, 30 Mar 2019 05:50:24 -0700 Subject: [PATCH 147/302] remove translations and fix readme --- CODE_OF_CONDUCT_FR.md | 47 ------ CONTRIBUTING_ES.md | 62 ------- CONTRIBUTING_FR.md | 65 -------- CONTRIBUTING_JP.md | 61 ------- CONTRIBUTING_KR.md | 66 -------- README.md | 4 +- README_CN.md | 321 ----------------------------------- README_ES.md | 379 ------------------------------------------ README_FR.md | 379 ------------------------------------------ README_GE.md | 361 ---------------------------------------- README_JP.md | 353 --------------------------------------- README_KR.md | 348 -------------------------------------- README_PTBR.md | 363 ---------------------------------------- 13 files changed, 1 insertion(+), 2808 deletions(-) delete mode 100644 CODE_OF_CONDUCT_FR.md delete mode 100644 CONTRIBUTING_ES.md delete mode 100644 CONTRIBUTING_FR.md delete mode 100644 CONTRIBUTING_JP.md delete mode 100644 CONTRIBUTING_KR.md delete mode 100644 README_CN.md delete mode 100644 README_ES.md delete mode 100644 README_FR.md delete mode 100644 README_GE.md delete mode 100644 README_JP.md delete mode 100644 README_KR.md delete mode 100644 README_PTBR.md diff --git a/CODE_OF_CONDUCT_FR.md b/CODE_OF_CONDUCT_FR.md deleted file mode 100644 index 5f870ced1..000000000 --- a/CODE_OF_CONDUCT_FR.md +++ /dev/null @@ -1,47 +0,0 @@ -# Code de conduite à l'attention des contributeurs - -## Notre engagement - -Dans le but de favoriser un environnement ouvert et accueillant, nous nous engageons à faire de la participation à ce projet et à cette communauté une expérience sans harcèlement, peu importe l'âge, la taille, le handicap, l'origine ethnique, l'identité et l'expression sexuelle, le niveau d'expérience, la nationalité, l'apparence personnelle, la race, la religion ou l'identité et l'orientation sexuelles. - -## Nos normes - -Voici quelques exemples de comportements qui contribuent à créer un environnement positif : - -* Utiliser un langage accueillant et inclusif -* Être respectueux des différents points de vue et expériences. -* Accepter dignement les critiques constructives -* Se concentrer sur ce qu'il y a de mieux pour la communauté. -* Faire preuve d'empathie envers les autres membres de la communauté. - -Voici quelques exemples de comportements inacceptables de la part des participants : - -* Le recours à un langage ou à des images de nature sexuelle et une attention ou des avances sexuelles mal venues. -* Trolling, commentaires désobligeants ou insultants et attaques personnelles ou politiques. -* Harcelement public ou privé -* Publier les informations privées d'autres personnes, telles qu'une adresse physique ou électronique, sans autorisation explicite. -* Tout autre comportement qui pourrait raisonnablement être considéré comme inapproprié dans un cadre professionnel. - - -## Nos responsabilités - -Les mainteneurs de projet sont responsables de clarifier les normes de comportement acceptable et on s'attend à ce qu'ils prennent des mesures correctives appropriées et équitables en réponse à tout cas de comportement inacceptable. - -Les mainteneurs de projet ont le droit et la responsabilité de supprimer, éditer ou rejeter les commentaires, les engagements, le code, les modifications wiki, les problèmes et autres contributions qui ne sont pas alignés sur ce code de conduite, ou d'interdire temporairement ou définitivement tout contributeur pour d'autres comportements qu'ils jugent inappropriés, menaçants, offensants ou nuisibles. - -## Champ d'application - -Le présent Code de conduite s'applique à la fois dans les espaces du projet et dans les espaces publics lorsqu'une personne représente le projet ou sa communauté. Les exemples de représentation d'un projet ou d'une communauté comprennent l'utilisation d'une adresse électronique officielle du projet, l'affichage par l'intermédiaire d'un compte officiel des médias sociaux ou le fait d'agir en tant que représentant désigné lors d'un événement en ligne ou hors ligne. La représentation d'un projet peut être définie et clarifiée par les responsables du projet. - -## Exécution - -Les cas de comportement abusif, de harcèlement ou d'autres comportements inacceptables peuvent être signalés en contactant l'équipe du projet à kwk236@gmail.com. L'équipe de projet examinera et enquêtera sur toutes les plaintes et répondra d'une manière qu'elle jugera appropriée aux circonstances. L'équipe de projet est tenue de respecter la confidentialité à l'égard du déclarant d'un incident. D'autres détails sur des politiques d'application spécifiques peuvent être affichés séparément. - -Les mainteneurs de projet qui ne suivent pas ou n'appliquent pas le Code de conduite de bonne foi peuvent faire face à des répercussions temporaires ou permanentes déterminées par d'autres membres de la direction du projet. - -## Attribution - -Le présent Code de conduite est une adaptation de la[Contributor Covenant][homepage], version 1.4, disponible à [http://contributor-covenant.org/version/1/4][version] - -[page principale]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING_ES.md b/CONTRIBUTING_ES.md deleted file mode 100644 index 578b1d4b7..000000000 --- a/CONTRIBUTING_ES.md +++ /dev/null @@ -1,62 +0,0 @@ -# Contribuyendo - -Nos encantan los pull requests de todos. Al contribuir a este repositorio, usted acepta cumplir con el [Código de Conducta](CODE_OF_CONDUCT.md). - -## Comenzando - -* Primero haga un [fork][fork] del repositorio y luego clónelo usando: - - git clone git@github.com:your-username/algorithms.git - -* Después de eso, crea una git branch para tus cambios. Por ejemplo: - * add_XXX Si agregara nuevos algoritmos o estructuras de datos. - * fix_XXX Si arreglará un error en un determinado algoritmo o estructura de datos. - * test_XXX Si escribiste una o más pruebas. - * doc_XXX Si ha editado o añadido a la documentación. - -Usted puede contribuir: -- Implementando nuevos algoritmos en el repositorio. Asegúrese de ponerlo en la sección correcta (ej. [array](array), [dp](dp), etc). Cree una nueva sección para él si no cae en ninguna. Asegúrese de que su implementación funciona. -- Optimizando o mejorando los algoritmos existentes. -- Añadiendo una solución diferente para el problema. -- Encontrando y corrigiendo errores. -- Añadiendo ejemplos para explicar mejor los algoritmos. -- Añadiendo casos de prueba. -- Mejorando la documentación. - -## Pull Requests -Haga push a su fork y [envie un pull request][pr]. - -Revisaremos y sugeriremos algunos cambios, mejoras o alternativas. Algunas cosas que aumentarán la posibilidad de que su pull request sea aceptado: - - -* Todos los algoritmos deben estar escritos en **Python 3**. -(Hay algunos algoritmos todavía con la sintaxis de _Python 2_. Puede comenzar con la conversión de [aquellos][issue120] a _Python 3_.) -* Escribir código limpio y comprensible. -* Comente correctamente el código y explique brevemente qué está haciendo el algoritmo en los [docstrings][docstr]. -* También puede explicar la salida usando un ejemplo mínimo. -* Trate de incluir también un par de casos de prueba para el algoritmo. -* Escriba un [buen mensaje en el commit][commit]. - - -## Issues -Envíe un [nuevo issue][newissue] si hay un algoritmo por agregar, o si se encontró un error en un algoritmo existente. Antes de enviar un nuevo issue, revise lo [issues existentes][issues] para evitar crear duplicados. También, considere resolver problemas actuales o contribuir a la discusión sobre un tema. - -## Colaboradores -Puedes pedir ayuda o aclaraciones a los colaboradores. -[Keon Kim](https://github.com/keon) - -[Rahul Goswami](https://github.com/goswami-rahul) - -[Ankit Agarwal](https://github.com/ankit167) - -[Hai Hoang Dang](https://github.com/danghai) - -[Saad](https://github.com/SaadBenn) - -[fork]: https://help.github.com/articles/fork-a-repo/ -[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings -[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[pr]: https://github.com/keon/algorithms/compare/ -[newissue]: https://github.com/keon/algorithms/issues/new -[issue120]: https://github.com/keon/algorithms/issues/120 -[issues]: https://github.com/keon/algorithms/issues/ diff --git a/CONTRIBUTING_FR.md b/CONTRIBUTING_FR.md deleted file mode 100644 index 9fe4bef95..000000000 --- a/CONTRIBUTING_FR.md +++ /dev/null @@ -1,65 +0,0 @@ -# Contribuer - -Nous aimons les contributions (sous la forme de pull requests). En contribuant à ce repertoire, vous acceptez de suivre les -règles du [Code de conduite](CODE_OF_CONDUCT_FR.md). - -## Mise en route - -* Dans un premier temps [forkez][fork] le repertoire puis clonez le grâce à la commande: - - git clone git@github.com:votre-pseudo-github/algorithms.git - -* Ensuite, créez une nouvelle branche dans laquelle vous effectuerez vos changements. For example: - * add_XXX si vous allez ajouter de nouveaux algorithmes ou de nouvelles structures de données. - * fix_XXX si vous allez corriger un bogue sur un certain algorithme ou structure de données. - * test_XXX si vous avez écrit un ou des tests. - * doc_XXX si vous avez ajouté ou édité de la documentation. - -Vous pouvez contribuer en : -- implémenter un nouvel algorithme dans ce repertoire. Faites bien attention à -le mettre dans la bonne section (i.e. [array](array), [dp](dp), etc). Vous pouvez créer une nouvelle -section si besoin. Assurez-vous que votre implémentation fonctionne, -- optimisant et en améliorant les algorithmes déjà présents, -- ajoutant de nouvelles solutions aux problèmes, -- trouvant et corrigeant des bogues, -- ajoutant des exemples afin de mieux expliquer le fonctionnement des algorithmes, -- ajoutant des tests, -- améliorant la documentation. - -## Pull Requests -Poussez votre fork sur git et [soumettez une nouvelle pull request][pr]. -Nous examinerons et pourrons suggérer des changements, des améliorations ou des solutions de rechange. -Pour faciliter l'acceptation, vous pouvez vérifier que : - -* tous les algorithmes doivent être écrits en **Python 3**, -(il reste encore quelques algorithmes écrits en _Python 2_. Vous pouvez commencer par convertir ces -[derniers][issue120] vers du _Python 3_), -* écrire un code propre et compréhensible, -* commenter correctement le code et expliquer brièvement ce que l'algorithme fait dans la [documentation][docstr], -* vous pouvez également expliquer le résultat à l'aide d'un exemple simple. -* essayer d'écrire quelques tests pour les algorithmes, -* écrire un [message de soumission (commit) clair][commit]. - - -## Problèmes -Soumettez une [nouveau issue][newissue] s'il y a un algorithme à ajouter, ou si un bogue a été trouvé dans un algorithme existant. Avant d'en soumettre une nouvelle, veuillez passer en revue les [issues existantes][issues] afin d'éviter de créer des doublons. Envisagez également de résoudre des issues actuellement ouvertes ou de contribuer à la discussion sur une issue. - -## Collaborateurs -Vous pouvez demander de l'aide ou des éclaircissements aux collaborateurs. -[Keon Kim](https://github.com/keon) - -[Rahul Goswami](https://github.com/goswami-rahul) - -[Ankit Agarwal](https://github.com/ankit167) - -[Hai Hoang Dang](https://github.com/danghai) - -[Saad](https://github.com/SaadBenn) - -[fork]: https://help.github.com/articles/fork-a-repo/ -[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings -[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[pr]: https://github.com/keon/algorithms/compare/ -[newissue]: https://github.com/keon/algorithms/issues/new -[issue120]: https://github.com/keon/algorithms/issues/120 -[issues]: https://github.com/keon/algorithms/issues/ diff --git a/CONTRIBUTING_JP.md b/CONTRIBUTING_JP.md deleted file mode 100644 index a8e46c238..000000000 --- a/CONTRIBUTING_JP.md +++ /dev/null @@ -1,61 +0,0 @@ -# 貢献 - -私たちは、誰からもプルリクエストを歓迎します。このレポジトリに貢献をするためには[Code of Conduct](CODE_OF_CONDUCT.md)を従うことを同意しなければなりません。 - -## 始める - -* まずリポジトリを[フォーク][fork]し,次を使用してクローンします. - - git clone git@github.com:your-username/algorithms.git - -* その後,変更のためのブランチを作成します. 例えば: - * add_XXX : 新しいアルゴリズムやデータ構造を追加する場合 - * fix_XXX : 特定のアルゴリズムやデータ構造のbugを修正する場合 - * test_XXX : テストを作成する場合 - -以下の方法で貢献できます: -- レポジトリの新しいアルゴリズムを開発すること。 正しいセクションに保存してください(例: [array](array), [dp](dp), 等)。 どのセクションにも該当しない場合は、新しいセクションを作成します。 また、コードが正常に作動するかどうか確認してください。 -- 既存のアルゴリズムの最適化または改善。 -- 問題の他のソリューションを追加。 -- バグの検索と修正。 -- アルゴリズムをよりよく説明するための例を追加。 -- テストケースの追加。 - -## プルリクエスト -フォークにプッシュして[プルリクエストを送信します][pr]。 - -私たちは、検討した後、変更、改善、代替案を提案することもできます。 -あなたのプルリクエストが受け入れられる可能性が高くなる方法: - -* すべてのアルゴリズムは**Python 3**で開発されなければなりません。 -(まだPython 2で作成されたアルゴリズムがいくつかあります。これらをPython 3に転換する作業でスタートすることもできます。) -* きれいで理解しやすいコードを作成する。 -* コードに適切なコメントを残して[docstrings][docstr]にアルゴリズムが何をしているのか簡単に説明する。 -* 小さな例を通じて出力を説明する。 -* アルゴリズムのテストケースをいくつか含ませる。 -* [good commit message][commit]を書く。 - - -## イシュー -追加するアルゴリズムがあったり、既存のアルゴリズムにバグが発見された場合の[new issue][newissue]を提出してください。 新たなイシューを提出する前に重複を避けるために、[existing issues][issues]を確認してください。 また、現在のイシューを解決したり論議中のイシューに貢献することも考慮してください。 - -## コラボレータ -コラボレータには,どのようなヘルプや説明も求めることができます. - -[Keon Kim](https://github.com/keon) - -[Rahul Goswami](https://github.com/goswami-rahul) - -[Ankit Agarwal](https://github.com/ankit167) - -[Hai Hoang Dang](https://github.com/danghai) - -[Saad](https://github.com/SaadBenn) - -[fork]: https://help.github.com/articles/fork-a-repo/ -[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings -[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[pr]: https://github.com/keon/algorithms/compare/ -[newissue]: https://github.com/keon/algorithms/issues/new -[issue120]: https://github.com/keon/algorithms/issues/120 -[issues]: https://github.com/keon/algorithms/issues/ diff --git a/CONTRIBUTING_KR.md b/CONTRIBUTING_KR.md deleted file mode 100644 index 522f0e5b9..000000000 --- a/CONTRIBUTING_KR.md +++ /dev/null @@ -1,66 +0,0 @@ -# 기여 활동 - -모든 pull request는 환영입니다. 이 저장소에 기여 함으로써, 당신은 [code of conduct](CODE_OF_CONDUCT.md) -를 준수하는 것에 동의 한 것입니다. - - -## 시작하기 - -* 우선 이 저장소를 [fork][fork] 하시고, 이를 사용하기 위해서 다음과 같이 clone 주세요: - - git clone git@github.com:your-username/algorithms.git - -* 그리고 새로운 내용을 더할 branch를 만들어주세요. 예를 들어: - * add_XXX 만약 당신이 새로운 알고리즘이나 자료 구조를 추가 했을 경우. - * fix_XXX 만약 당신이 어떤 알고리즘이나 자료 구조에서 고쳐야할 bug를 발견했을 경우. - * test_XXX 만약 당신이 test/s를 작성한 경우. - -당신은 다음과 같이 기여할 수 있습니다: -- 새로운 알고리즘을 구현해주세요. 그리고, 그것을 정확히 분류해주세요(e.g. [array](array), [dp](dp), etc). -만약 당신의 알고리즘이 어떤 섹션에도 포함이 되지 않는다면, 새로운 섹션을 만들어 주세요. 단, 당신의 알고리즘이 제대로 작동하는지 -확인해주세요. -- 알고리즘들을 최적화하거나 향상시켜주세요. -- 문제들에 대해서 다른 해결 법을 추가해주세요. -- 버그들을 찾거나 고쳐주세요. -- 알고리즘들을 더 잘 설명하기 위한 새로운 예시들을 추가해주세요. -- test cases를 추가해주세요. - -## Pull Requests -당신의 fork에 push 하고 pull request를 제출하세요 [submit a pull request][pr]. - -우리는 이를 검토할 것이며, 변화, 개량, 혹은 대안을 제시할 수 도 있습니다. -여기에 당신의 pull request가 허용될 가능성을 높여주는 몇몇 요소들이 있습니다: - -* 모든 알고리즘들은 **Python 3**로 작성되어야 합니다. -(몇몇 알고리즘들은 여전히 _python 2_ 로 작성되어져 있습니다. 당신은 이를 Python 3으로 번역함으로써 저희에게 기여 해주실 수도 있습니다. -[those][issue120] to _Python 3_.) -* 깔끔하고 이해할 수 있는 코드를 작성해주세요. -* 코드에 대해 올바르게 주석 처리 해 주시고, 알고리즘이 수행하는 작업에 대해서 [docstrings][docstr]에서 설명해 주세요. -* 당신은 간단한 예시를 제시함으로써 출력 값에 대하여 설명하실 수도 있습니다. -* 또한 가능하다면 알고리즘에 대하여, 두 가지의 test cases를 포함 시켜주세요. -* [good commit message][commit]를 작성해주세요. - - -## Issues -만약 추가해야 할 알고리즘이 있거나, 현재 저희 프로젝트의 어떤 알고리즘에서 버그가 발견된다면 [new issue][newissue]에 이를 추가해주세요. 새로운 issue를 제안하기 전에 중복된 issue을 발생을 피하기 위해서 [existing issues][issues]를 확인해주세요. 또한, 현재 존재하는 issue를 해결하는 것을 고려해주시거나 issue에 대한 토의에 기여해주세요. - -## Collaborators -저희 협업자 들에게 어떤 도움이나 확인이 필요하다면, 위 주소로 물어봐주세요. - -[Keon Kim](https://github.com/keon) - -[Rahul Goswami](https://github.com/goswami-rahul) - -[Ankit Agarwal](https://github.com/ankit167) - -[Hai Hoang Dang](https://github.com/danghai) - -[Saad](https://github.com/SaadBenn) - -[fork]: https://help.github.com/articles/fork-a-repo/ -[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings -[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[pr]: https://github.com/keon/algorithms/compare/ -[newissue]: https://github.com/keon/algorithms/issues/new -[issue120]: https://github.com/keon/algorithms/issues/120 -[issues]: https://github.com/keon/algorithms/issues/ diff --git a/README.md b/README.md index 48d4c7f7c..229114e0f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@

-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) - [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) @@ -219,7 +217,7 @@ If you want to uninstall algorithms, it is as simple as: - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py) - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) diff --git a/README_CN.md b/README_CN.md deleted file mode 100644 index ca181d613..000000000 --- a/README_CN.md +++ /dev/null @@ -1,321 +0,0 @@ -

- -[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) - -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Python版数据结构和算法 -========================================= - -python版数据结构和算法实现的简约版小示例 - -谢谢关注。有多种方法可以贡献你的代码。[从这里开始吧](https://github.com/keon/algorithms/blob/master/CONTRIBUTING.md) - -[或者可以用不同语言来完成上述算法,期待加入](https://github.com/yunshuipiao/sw-algorithms):https://github.com/yunshuipiao/sw-algorithms - -## 测试 - -### 单元测试 -如下代码可以运行全部测试: -``` - -python3 -m unittest discover tests - -``` - -针对特定模块(比如:sort)的测试, 可以使用如下代码: -``` - -python3 -m unittest tests.test_sort - -``` - -### 使用pytest -如下代码运行所有测试代码: -``` - -python3 -m pytest tests - -``` - -## 安装 -如果想在代码中使用算法API, 可按如下步骤进行: -``` - -pip3 install git+https://github.com/keon/algorithms - -``` - -通过创建python文件(比如:在sort模块使用merge_sort)进行测试: -``` - -from algorithms.sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort(my_list) - print(my_list) - -``` - -## 卸载 -如下代码可卸载该API: - -``` - -pip3 uninstall -y algorithms - -``` - -## 实现列表 - -- [array:数组](arrays) - - [delete_nth: 删除第n项](algorithms/arrays/delete_nth.py) - - [flatten:数组降维](algorithms/arrays/flatten.py) - - [garage:停车场](algorithms/arrays/garage.py) - - [josephus_problem: 约瑟夫问题](algorithms/arrays/josephus.py) - - [max_ones_index:最长1串索引](algorithms/arrays/max_ones_index.py) - - [limit:数组过滤](algorithms/arrays/limit.py) - - [longest_non_repeat:最长不重复子串](algorithms/arrays/longest_non_repeat.py/) - - [merge_intervals:合并重叠间隔](algorithms/arrays/merge_intervals.py) - - [missing_ranges:遗失的范围](algorithms/arrays/missing_ranges.py) - - [plus_one:加一运算](algorithms/arrays/plus_one.py) - - [rotate:反转数组](algorithms/arrays/rotate.py) - - [summarize_ranges:数组范围](algorithms/arrays/summarize_ranges.py) - - [three_sum:三数和为零](algorithms/arrays/three_sum.py) - - [trimmean:按比取均值](algorithms/arrays/trimmean.py) - - [top_1:出现次数最多的元素](algorithms/arrays/top_1.py) - - [two_sum:两数和](algorithms/arrays/two_sum.py) - - [move_zeros: 0后置问题](algorithms/arrays/move_zeros.py) - - [n_sum](algorithms/arrays/n_sum.py) -- [backtrack:回溯](algorithms/backtrack) - - [general_solution.md:一般方法](algorithms/backtrack/) - - [add_operators:](algorithms/backtrack/add_operators.py) - - [anagram:同字母异序词](algorithms/backtrack/anagram.py) - - [array_sum_combinations:数组和](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum:和的合并](algorithms/backtrack/combination_sum.py) - - [expression_add_operators:给表达式添加运算符](algorithms/backtrack/expression_add_operators.py) - - [factor_combinations:因素组合](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations:缩写生成](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis:括号生成](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination:字母组合](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning:字符串的所有回文子串](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match:模式匹配](algorithms/backtrack/pattern_match.py) - - [permute:排列](algorithms/backtrack/permute.py) - - [permute_unique:唯一排列](algorithms/backtrack/permute_unique.py) - - [subsets:子集](algorithms/backtrack/subsets.py) - - [subsets_unique:唯一子集](algorithms/backtrack/subsets_unique.py) -- [bfs:广度优先搜索](algorithms/bfs) - - [maze_search:迷宫的最短路径](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings:所有建筑物的最短路径](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder:词语阶梯](algorithms/bfs/word_ladder.py) -- [bit:位操作](algorithms/bit) - - [bytes_int_conversion:字节整数转换](algorithms/bit/bytes_int_conversion.py) - - [count_ones:统计1出现的次数](algorithms/bit/count_ones.py) - - [count_flips_to_convert:不同的比特位](algorithms/bit/count_flips_to_convert.py) - - [find_missing_number:寻找缺失数](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence:最长1串长度](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two:2的n次方数判断](algorithms/bit/power_of_two.py) - - [reverse_bits:反转位](algorithms/bit/reverse_bits.py) - - [single_number2:寻找出现1次的数(2)](algorithms/bit/single_number2.py) - - [single_number:寻找出现1次的数(1)](algorithms/bit/single_number.py) - - [subsets: 求所有子集](algorithms/bit/subsets.py) - - [add_bitwise_operator:无操作符的加法](algorithms/bit/add_bitwise_operator.py) -- [calculator:计算](algorithms/calculator) - - [math_parser: 数字解析](algorithms/calculator/math_parser.py) -- [dfs:深度优先搜索](algorithms/dfs) - - [all_factors:因素分解](algorithms/dfs/all_factors.py) - - [count_islands:岛计数](algorithms/dfs/count_islands.py) - - [pacific_atlantic:太平洋大西洋](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver:数独解法](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates:墙和门](algorithms/dfs/walls_and_gates.py) -- [dp:动态规划](algorithms/dp) - - [buy_sell_stock:股票买卖](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs:爬梯子问题](algorithms/dp/climbing_stairs.py) - - [combination_sum:和组合问题](algorithms/dp/combination_sum.py) - - [house_robber:打家劫舍](algorithms/dp/house_robber.py) - - [knapsack:背包问题](algorithms/dp/knapsack.py) - - [longest_increasing:最长递增子序列](algorithms/dp/longest_increasing.py) - - [max_product_subarray:最大子数组乘积](algorithms/dp/max_product_subarray.py) - - [max_subarray:最大子数组](algorithms/dp/max_subarray.py) - - [num_decodings:数字解码](algorithms/dp/num_decodings.py) - - [regex_matching:正则匹配](algorithms/dp/regex_matching.py) - - [word_break:单词分割](algorithms/dp/word_break.py) -- [graph:图](graph) - - [check_bipartite:二分图](algorithms/graph/check_bipartite.py) - - [2-sat:2-sat](algorithms/graph/satisfiability.py) - - [clone_graph:克隆图](algorithms/graph/clone_graph.py) - - [cycle_detection:判断圈算法](algorithms/graph/cycle_detection.py) - - [find_path:发现路径](algorithms/graph/find_path.py) - - [graph:图](algorithms/graph/graph.py) - - [traversal:遍历](algorithms/graph/traversal.py) - - [markov_chain:马尔可夫链](algorithms/graph/markov_chain.py) -- [heap:堆](algorithms/heap) - - [merge_sorted_k_lists:合并k个有序链](algorithms/heap/merge_sorted_k_lists.py) - - [skyline:天际线](algorithms/heap/skyline.py) - - [sliding_window_max:滑动窗口最大值](algorithms/heap/sliding_window_max.py) -- [iterables : 迭代](algorithms/iterables) - - [convolved : 卷积](algorithms/iterables/convolved.py) -- [linkedlist:链表](algorithms/linkedlist) - - [add_two_numbers:链表数相加](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer:复制带有随机指针的链表](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node:删除节点](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node:环链表的第一个节点](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic:判断环链表](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome:回文链表](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last:倒数第k个节点](algorithms/linkedlist/kth_to_last.py) - - [linkedlist: 链表](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates:删除重复元素](algorithms/linkedlist/remove_duplicates.py) - - [reverse:反转链表](algorithms/linkedlist/reverse.py) - - [rotate_list:旋转链表](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs:链表节点交换](algorithms/linkedlist/swap_in_pairs.py) -- [map:映射](algorithms/map) - - [hashtable:哈希表](algorithms/map/hashtable.py) - - [separate_chaining_hashtable:拉链法哈希表](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence:最长公共子序列](algorithms/map/longest_common_subsequence.py) - - [randomized_set:随机集](algorithms/map/randomized_set.py) - - [valid_sudoku:有效数独](algorithms/map/valid_sudoku.py) -- [math:数学问题](algorithms/maths) - - [extended_gcd:扩展欧几里得算法](algorithms/maths/extended_gcd.py) - - [combination:组合数](algorithms/maths/combination.py) - - [factorial:阶乘](algorithms/maths/factorial.py) - - [gcd/lcm:最大公约数和最小公倍数](algorithms/maths/gcd.py) - - [prime_test:主要测试](algorithms/maths/prime_test.py) - - [primes_sieve_of_eratosthenes:埃拉托色尼的质数筛](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [generate_strobogrammtic:生成对称数](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic:判断对称数](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential:m的n次方](algorithms/maths/modular_exponential.py) - - [nth_digit:第n位](algorithms/maths/nth_digit.py) - - [rabin_miller:米勒-拉宾素性检验](algorithms/maths/rabin_miller.py) - - [rsa:rsa加密](algorithms/maths/rsa.py) - - [sqrt_precision_factor:开发精度因素](algorithms/maths/sqrt_precision_factor.py) - - [pythagoras:毕达哥拉斯](algorithms/maths/pythagoras.py) -- [matrix:矩阵](algorithms/matrix) - - [matrix_rotation:矩阵旋转](algorithms/matrix/matrix_rotation.txt) - - [copy_transform:复制变换](algorithms/matrix/copy_transform.py) - - [bomb_enemy:炸弹人](algorithms/matrix/bomb_enemy.py) - - [rotate_image:旋转图像](algorithms/matrix/rotate_image.py) - - [sparse_dot_vector:解析点向量](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul:稀疏矩阵](algorithms/matrix/sparse_mul.py) - - [spiral_traversal:循环遍历](algorithms/matrix/spiral_traversal.py) - - [count_paths:计算路径](algorithms/matrix/count_paths.py) -- [queue:队列](algorithms/queues) - - [max_sliding_window:最大移动窗口](algorithms/queues/max_sliding_window.py) - - [moving_average:移动平均](algorithms/queues/moving_average.py) - - [queue:队列](algorithms/queues/queue.py) - - [reconstruct_queue:重建队列](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator:锯齿形迭代](algorithms/queues/zigzagiterator.py) -- [search:查找](algorithms/search) - - [binary_search:二分查找](algorithms/search/binary_search.py) - - [count_elem:元素计数](algorithms/search/count_elem.py) - - [first_occurance:首次出现](algorithms/search/first_occurance.py) - - [last_occurance:最后一次出现](algorithms/search/last_occurance.py) - - [linear_search:线性搜索](algorithms/search/linear_search.py) - - [jump_search:跳跃搜索](algorithms/search/jump_search.py) -- [set:集合](algorithms/set) - - [randomized_set:随机集合](algorithms/set/randomized_set.py) - - [set_covering:集合覆盖](algorithms/set/set_covering.py) -- [sort:排序](algorithms/sort) - - [bitonic_sort:双调排序](algorithms/sort/bitonic_sort.py) - - [bogo_sort:猴子排序](algorithms/sort/bogo_sort.py) - - [bubble_sort:冒泡排序](algorithms/sort/bubble_sort.py) - - [bucket_sort:桶排序](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort:鸡尾酒排序](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort:梳排序](algorithms/sort/comb_sort.py) - - [counting_sort:计数排序](algorithms/sort/counting_sort.py) - - [cycle_sort:圈排序](algorithms/sort/cycle_sort.py) - - [gnome_sort:地精排序](algorithms/sort/gnome_sort.py) - - [heap_sort:堆排序](algorithms/sort/heap_sort.py) - - [insertion_sort:插入排序](algorithms/sort/insertion_sort.py) - - [meeting_rooms:会议室](algorithms/sort/meeting_rooms.py) - - [merge_sort:归并排序](algorithms/sort/merge_sort.py) - - [pancake_sort:煎饼排序](algorithms/sort/pancake_sort.py) - - [quick_sort:快速排序](algorithms/sort/quick_sort.py) - - [radix_sort:基数排序](algorithms/sort/radix_sort.py) - - [selection_sort:选择排序](algorithms/sort/selection_sort.py) - - [shell_sort:希尔排序](algorithms/sort/shell_sort.py) - - [sort_colors:颜色排序](algorithms/sort/sort_colors.py) - - [top_sort:top排序](algorithms/sort/top_sort.py) - - [wiggle_sort:摇摆排序](algorithms/sort/wiggle_sort.py) -- [stack:栈](algorithms/stack) - - [longest_abs_path:最长相对路径](algorithms/stack/longest_abs_path.py) - - [simplify_path:简化路径](algorithms/stack/simplify_path.py) - - [stack:栈](algorithms/stack/stack.py) - - [valid_parenthesis:验证括号](algorithms/stack/valid_parenthesis.py) -- [string:字符串](algorithms/strings) - - [add_binary:二进制数相加](algorithms/strings/add_binary.py) - - [breaking_bad:打破坏](algorithms/strings/breaking_bad.py) - - [decode_string:字符串编码](algorithms/strings/decode_string.py) - - [encode_decode:编解码](algorithms/strings/encode_decode.py) - - [group_anagrams:群组错位词](algorithms/strings/group_anagrams.py) - - [int_to_roman:整数转换罗马数字](algorithms/strings/int_to_roman.py) - - [is_palindrome:回文字符串](algorithms/strings/is_palindrome.py) - - [license_number:拍照号码](algorithms/strings/license_number.py) - - [make_sentence:造句](algorithms/strings/make_sentence.py) - - [multiply_strings:字符串相乘](algorithms/strings/multiply_strings.py) - - [one_edit_distance:一个编辑距离](algorithms/strings/one_edit_distance.py) - - [rabin_karp:Rabin-Karp 算法](algorithms/strings/rabin_karp.py) - - [reverse_string:反转字符串](algorithms/strings/reverse_string.py) - - [reverse_vowel:反转元音](algorithms/strings/reverse_vowel.py) - - [reverse_words:反转单词](algorithms/strings/reverse_words.py) - - [roman_to_int:罗马数转换整数](algorithms/strings/roman_to_int.py) - - [word_squares:单词平方](algorithms/strings/word_squares.py) -- [tree:树](algorithms/tree) - - [segment-tree:线段树](algorithms/tree/segment_tree) - - [segment_tree:线段树](algorithms/tree/segment_tree/segment_tree.py) - - [binary_tree_paths:二叉树路径](algorithms/tree/binary_tree_paths.py) - - [bintree2list:二叉树转换链表](algorithms/tree/bintree2list.py) - - [bst:二叉搜索树](algorithms/tree/tree/bst) - - [array2bst:数组转换](algorithms/tree/bst/array2bst.py) - - [bst_closest_value:最近二叉搜索树值](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator:二叉搜索树迭代](algorithms/tree/bst/BSTIterator.py) - - [delete_node:删除节点](algorithms/tree/bst/delete_node.py) - - [is_bst:判断二叉搜索树](algorithms/tree/bst/is_bst.py) - - [kth_smallest:二叉搜索树的第k小节点](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor:最近公共祖先](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor:前任](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize:序列化反序列化](algorithms/tree/bst/serialize_deserialize.py) - - [successor:继承者](algorithms/tree/bst/successor.py) - - [unique_bst:唯一BST](algorithms/tree/bst/unique_bst.py) - - [deepest_left:最深叶子节点](algorithms/tree/deepest_left.py) - - [invert_tree:反转树](algorithms/tree/invert_tree.py) - - [is_balanced:判断平衡树](algorithms/tree/is_balanced.py) - - [is_subtree:判断子树](algorithms/tree/is_subtree.py) - - [is_symmetric:判断对称树](algorithms/tree/is_symmetric.py) - - [longest_consecutive:最长连续节点](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor:最近公共祖先](algorithms/tree/lowest_common_ancestor.py) - - [max_height:最大高度](algorithms/tree/max_height.py) - - [max_path_sum:最长路径和](algorithms/tree/max_path_sum.py) - - [min_height:最小高度](algorithms/tree/min_height.py) - - [path_sum2:路径和2](algorithms/tree/path_sum2.py) - - [path_sum:路径和](algorithms/tree/path_sum.py) - - [pretty_print:完美打印](algorithms/tree/pretty_print.py) - - [same_tree:相同树](algorithms/tree/same_tree.py) - - [traversal:遍历](algorithms/tree/traversal) - - [inorder:中序遍历](algorithms/tree/traversal/inorder.py) - - [level_order:层次遍历](algorithms/tree/traversal/level_order.py) - - [postorder:后序遍历](algorithms/tree/traversal/postorder.py) - - [preorder:前序遍历](algorithms/tree/traversal/preorder.py) - - [zigzag:锯齿形遍历](algorithms/tree/traversal/zigzag.py) - - [tree:树](algorithms/tree/tree.py) - - [trie:字典树](algorithms/tree/trie) - - [add_and_search:添加和查找](algorithms/tree/trie/add_and_search.py) - - [trie:字典](algorithms/tree/trie/trie.py) -- [union-find:并查集](algorithms/union-find) - - [count_islands:岛计数](algorithms/union-find/count_islands.py) - - -## 贡献 -谢谢主要维护人员: - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -以及[所有贡献者](https://github.com/keon/algorithms/graphs/contributors) diff --git a/README_ES.md b/README_ES.md deleted file mode 100644 index 045c332f4..000000000 --- a/README_ES.md +++ /dev/null @@ -1,379 +0,0 @@ -

- -[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | Español - -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Estructuras de datos y algoritmos en Python -========================================= - -Ejemplo de implementaciones mínimas y limpias de estructuras de datos y algoritmos en Python 3. - -## Contribuciones -¡Gracias por su interés en contribuir! Hay muchas maneras de contribuir a este proyecto. [Comienza aquí](CONTRIBUTING_ES.md) - -## Pruebas - -### Usando unittest -Escriba lo siguiente para ejecutar todas las pruebas: - - $ python3 -m unittest discover tests - -Para ejecutar pruebas en específico, puede hacerlo de la siguiente manera (Ej: sort): - - $ python3 -m unittest tests.test_sort - -### Usando pytest -Escriba lo siguiente para ejecutar todas las pruebas: - - $ python3 -m pytest tests - -## Instalación -Si desea utilizar el API algorithms en su código, es tan simple como: - - $ pip3 install algorithms - -Puede probar creando un archivo python: (Ej: use `merge_sort` en `sort`) - -```python3 -from algorithms.sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort(my_list) - print(my_list) -``` - -## Desinstalación -Si desea desinstalar algorithms, es tan simple como: - - $ pip3 uninstall -y algorithms - -## Lista de immplementaciones - -- [arrays](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) - - [n_sum](algorithms/arrays/n_sum.py) -- [backtrack](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [add_operators](algorithms/backtrack/add_operators.py) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit](algorithms/bit) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [count_ones](algorithms/bit/count_ones.py) - - [find_difference](algorithms/bit/find_difference.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) - - [binary_gap](algorithms/bit/binary_gap.py) -- [calculator](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) -- [dfs](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [dp](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) -- [graph](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) -- [heap](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) -- [linkedlist](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) - - [word_pattern](algorithms/map/word_pattern.py) - - [is_isomorphic](algorithms/map/is_isomorphic.py) - - [is_anagram](algorithms/map/is_anagram.py) -- [maths](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [combination](algorithms/maths/combination.py) - - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - - [euler_totient](algorithms/maths/euler_totient.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) -- [matrix](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py -- [queues](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurrence](algorithms/search/first_occurrence.py) - - [last_occurrence](algorithms/search/last_occurrence.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) - - [next_greatest_letter](algorithms/search/next_greatest_letter.py) -- [set](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) - - [find_keyboard_row](algorithms/set/find_keyboard_row.py) -- [sort](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [strings](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [unique_morse](algorithms/strings/unique_morse.py) - - [judge_circle](algorithms/strings/judge_circle.py) - - [strong_password](algorithms/strings/strong_password.py) - - [caesar_cipher](algorithms/strings/caesar_cipher.py) - - [contain_string](algorithms/strings/contain_string.py) - - [count_binary_substring](algorithms/strings/count_binary_substring.py) - - [repeat_string](algorithms/strings/repeat_string.py) - - [min_distance](algorithms/strings/min_distance.py) - - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) - - [rotate](algorithms/strings/rotate.py) - - [first_unique_char](algorithms/strings/first_unique_char.py) - - [repeat_substring](algorithms/strings/repeat_substring.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) -- [tree](algorithms/tree) - - [bst](algorithms/tree/bst) - - [array_to_bst](algorithms/tree/bst/array_to_bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [red_black_tree](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [traversal](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [unix](algorithms/unix) - - [path](algorithms/unix/path/) - - [join_with_slash](algorithms/unix/path/join_with_slash.py) - - [full_path](algorithms/unix/path/full_path.py) - - [split](algorithms/unix/path/split.py) - - [simplify_path](algorithms/unix/path/simplify_path.py) -- [union-find](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) -- [machine-learning](algorithms/machine-learning) - - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) - -## Colaboradores -El repositorio es mantenido por - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -Y gracias a [todos los colaboradores](https://github.com/keon/algorithms/graphs/contributors) -que ayudaron en la construcción del repositorio. diff --git a/README_FR.md b/README_FR.md deleted file mode 100644 index 99d445ad7..000000000 --- a/README_FR.md +++ /dev/null @@ -1,379 +0,0 @@ -

- -[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | Français | [Español](README_ES.md) - -[![Version PyPI](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Contributeurs open source](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Structures de données adaptées au Python et algorithmes -======================================================= - -Exemples simples et optimisés d'implémentations de structures de données et d'algorithmes en Python 3. - -## Contribuer -Merci de votre intérêt à contribuer ! Il y a plusieurs façons de contribuer à ce projet. [Commencez ici](CONTRIBUTING_FR.md) - -## Tests - -### Utilisation de unittest -Pour lancer tous les tests, saisissez la commande suivante : - $ python3 -m unittest discover tests - -Pour lancer des tests particuliers vous pouvez procéder comme suit(Ex: sort): - - $ python3 -m unittest tests.test_sort - -### Utilisation de pytest -Pour lancer tous les tests, saisissez la commande suivante : - - $ python3 -m pytest tests - -## Installation -Si vous voulez utiliser les algorithmes sous forme de paquet dans votre code, il suffit de faire ceci : - - $ pip3 install algorithms - -Vous pouvez tester votre installation en créant un fichier python : (Ex: utilisation de `merge_sort` dans `sort`) - -```python3 -from algorithms.sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort(my_list) - print(my_list) -``` - -## Désinstallation -Si vous voulez désinstaller le paquet algorithms, il suffit de procéder comme suit : - - $ pip3 uninstall -y algorithms - -## Liste des algorithmes - -- [arrays](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) - - [n_sum](algorithms/arrays/n_sum.py) -- [backtrack](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit](algorithms/bit) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [count_ones](algorithms/bit/count_ones.py) - - [find_difference](algorithms/bit/find_difference.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) - - [binary_gap](algorithms/bit/binary_gap.py) -- [calculator](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) -- [dfs](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [dp](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) -- [graph](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) -- [heap](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) -- [iterables](algorithms/iterables) - - [convolved](algorithms/iterables/convolved.py) -- [linkedlist](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) - - [word_pattern](algorithms/map/word_pattern.py) - - [is_isomorphic](algorithms/map/is_isomorphic.py) - - [is_anagram](algorithms/map/is_anagram.py) -- [maths](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [combination](algorithms/maths/combination.py) - - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) -- [matrix](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py -- [queues](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurance](algorithms/search/first_occurance.py) - - [last_occurance](algorithms/search/last_occurance.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) - - [next_greatest_letter](algorithms/search/next_greatest_letter.py) -- [set](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) - - [find_keyboard_row](algorithms/set/find_keyboard_row.py) -- [sort](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [strings](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [unique_morse](algorithms/strings/unique_morse.py) - - [judge_circle](algorithms/strings/judge_circle.py) - - [strong_password](algorithms/strings/strong_password.py) - - [caesar_cipher](algorithms/strings/caesar_cipher.py) - - [contain_string](algorithms/strings/contain_string.py) - - [count_binary_substring](algorithms/strings/count_binary_substring.py) - - [repeat_string](algorithms/strings/repeat_string.py) - - [min_distance](algorithms/strings/min_distance.py) - - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) - - [rotate](algorithms/strings/rotate.py) - - [first_unique_char](algorithms/strings/first_unique_char.py) - - [repeat_substring](algorithms/strings/repeat_substring.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) -- [tree](algorithms/tree) - - [bst](algorithms/tree/tree/bst) - - [array2bst](algorithms/tree/bst/array2bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [red_black_tree](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [traversal](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bintree2list](algorithms/tree/bintree2list.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [unix](algorithms/unix) - - [path](algorithms/unix/path/) - - [join_with_slash](algorithms/unix/path/join_with_slash.py) - - [full_path](algorithms/unix/path/full_path.py) - - [split](algorithms/unix/path/split.py) - - [simplify_path](algorithms/unix/path/simplify_path.py) -- [union-find](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) -- [machine-learning](algorithms/machine-learning) - - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) - -## Contributeurs -Ce répertoire est maintenu par - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -Et merci à[tous les contributeurs](https://github.com/keon/algorithms/graphs/contributors) -qui a aidé à construire le répertoire. diff --git a/README_GE.md b/README_GE.md deleted file mode 100644 index 91883c8ff..000000000 --- a/README_GE.md +++ /dev/null @@ -1,361 +0,0 @@ -

- -[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) - -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Pythonische Datenstrukturen und Algorithmen -========================================= - -In diesem Repository finden Sie eine große Auswahl an Algorithmen und Datenstrukturen implementiert in Python 3. - -## Beteiligen - -Sie können sich gerne auch an diesem Projekt beteiligen. Zum Beispiel selbst Algorithmen und Datenstrukturen beisteuern, oder bereits bestehende Implementierungen verbessern, oder auch dokumentieren. Fühlen Sie sich frei und machen Sie einen Pull-Request. Alternativ können Sie auch den Issue-Tracker benutzen um auf Probleme (Bugs) in bereits bestehenden Implementierungen hinzuweisen. - -In diesem Projekt halten wir uns an die [PEP8](https://www.python.org/dev/peps/pep-0008/) Codestyle Konventionen. - -## Tests - -### Benutzen der Unittests - -Um alle Tests laufen zu lassen, tippen Sie die unten stehende Befehlzeile in die Kommandozeile: - - $ python3 -m unittest discover tests - -Um einen besonderen Test laufen zu lassen, tippen Sie folgendes: - - $ python3 -m unittest tests.test_sort - -### Benutzen von pytest - -Zum ausführen aller Tests: - - $ python3 -m pytest tests - -## Install - -Wenn Sie das Projekt installieren wollen, um es als Module in Ihren Projekten nutzen zu können. Dann tippen Sie unten stehende Befehlzeile in die Kommandozeile: - - $ pip3 install git+https://github.com/keon/algorithms - -Sie können die Installation testen in dem Sie unten stehenden Code in eine Datei packen und ausführen. - -```python3 -from algorithms.sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort(my_list) - print(my_list) -``` - -## Uninstall - -Um das Projekt zu deinstallieren tippen Sie folgendes: - - $ pip3 uninstall -y algorithms - - -## Liste von Implementierungen - -- [arrays](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) -- [backtrack](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit](algorithms/bit) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_ones](algorithms/bit/count_ones.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [find_difference](algorithms/bit/find_difference.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) -- [calculator](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) -- [dfs](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [dp](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) -- [graph](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) -- [heap](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) -- [iterables](algorithms/iterables) - - [convolved](algorithms/iterables/convolved.py) -- [linkedlist](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) -- [maths](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [combination](algorithms/maths/combination.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) -- [matrix](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py -- [queues](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurance](algorithms/search/first_occurance.py) - - [last_occurance](algorithms/search/last_occurance.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) -- [set](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) -- [sort](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [strings](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) -- [tree](algorithms/tree) - - [bst](algorithms/tree/tree/bst) - - [array2bst](algorithms/tree/bst/array2bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [red_black_tree](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [traversal](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bintree2list](algorithms/tree/bintree2list.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [union-find](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) - -## Mitwirkende - -Das Projekt wird von folgenden Personen betreut. - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -Und danke an alle [Contributors](https://github.com/keon/algorithms/graphs/contributors) -die geholfen haben das Projekt aufzubauen! diff --git a/README_JP.md b/README_JP.md deleted file mode 100644 index 28f29cba8..000000000 --- a/README_JP.md +++ /dev/null @@ -1,353 +0,0 @@ -

- -[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) - -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Pythonのデータ構造とアルゴリズム -========================================= - -Python 3で開発された簡単で明確なデータ構造とアルゴリズムの例を紹介します。 - -## 貢献 -貢献に興味を持っていただきありがとうございます。 このプロジェクトに貢献する方法はたくさんあります。 - -[簡単にコミュニティへ貢献するには](CONTRIBUTING_JP.md) - -## テスト - -### unittestを使用 -すべてのテストを実行するには: - - $ python3 -m unittest discover tests - -特定のテストを実行するためには、(例: ソート): - - $ python3 -m unittest tests.test_sort - -### pytestを使用 -すべてのテストを実行するには: - - $ python3 -m pytest tests - -## インストール -自分のコードでAPIアルゴリズムを活用したい場合は、以下のコードで簡単に実行することができます。 - - $ pip3 install git+https://github.com/keon/algorithms - -Pythonファイルを作成してテストを実行することができます:(例:「sort」の「merge_sort」を使用) - -```python3 -from sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort.merge_sort(my_list) - print(my_list) -``` - -## 削除 -アルゴリズムを削除する場合は、次のコードで簡単に実行することができます: - - $ pip3 uninstall -y algorithms - -## アルゴリズムのリスト - -- [arrays : 配列](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) -- [backtrack : バックトラッキング](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs : 幅優先探索](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit : ビット](algorithms/bit) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_ones](algorithms/bit/count_ones.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [find_difference](algorithms/bit/find_difference.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) -- [calculator : 計算機](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) -- [dfs : 深さ優先探索](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [dp : 動的計画法](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) -- [graph : グラフ](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) -- [heap : ヒープ](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) -- [iterables : 繰り返し可能な](algorithms/iterables) - - [convolved](algorithms/iterables/convolved.py) -- [linkedlist : 連結リスト](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map : マップ](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) -- [maths : 数学](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [combination](algorithms/maths/combination.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) -- [matrix : 行列](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py -- [queues : キュー](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search : サーチ](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurance](algorithms/search/first_occurance.py) - - [last_occurance](algorithms/search/last_occurance.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) -- [set : セット](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) -- [sort : ソート](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack : スタック](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [strings : 文字列](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) -- [tree : 木構造](algorithms/tree) - - [bst](algorithms/tree/tree/bst) - - [array2bst](algorithms/tree/bst/array2bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [red_black_tree](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [traversal](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bintree2list](algorithms/tree/bintree2list.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [union-find : 素集合データ構造](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) - -## 貢献者 -本リポジトリは次の方によって維持されています - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -また、[全ての貢献者](https://github.com/keon/algorithms/graphs/contributors)に感謝を伝えます。 diff --git a/README_KR.md b/README_KR.md deleted file mode 100644 index ab4ce7790..000000000 --- a/README_KR.md +++ /dev/null @@ -1,348 +0,0 @@ -

- -[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md) - -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Python 버전 자료구조 및 알고리즘 -========================================= - -Python 3로 구현한 간단하고 명확한 자료구조와 알고리즘들의 예제 입니다. - -## 기여 활동 -프로젝트 활동 참여에 관심을 가져주셔서 감사합니다! 여러가지 방법으로 이 프로젝트에 기여해주세요. [기여 방법 소개](CONTRIBUTING.md) - -## 테스트 종류들 - -### unittest 사용 -아래 명시된 모든 테스트 실행하기: - - $ python3 -m unittest discover tests - -특정 테스트 실행하기 위해선 아래 코드로 실행할 수 있습니다 (예시: sort): - - $ python3 -m unittest tests.test_sort - -### pytest 사용 -아래 명시된 모든 테스트 실행하기: - - $ python3 -m pytest tests - -## 알고리즘 설치 -만약 API 알고리즘들을 당신의 코드에 사용하기를 원한다면, 아래 코드로 간단하게 실행할 수 있습니다: - - $ pip3 install git+https://github.com/keon/algorithms - -그리고 python 파일을 만듦으로 테스트할 수 있습니다: (예시: 'sort'안에서 'merge_sort'사용) - -```python3 -from sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort.merge_sort(my_list) - print(my_list) -``` - -## 알고리즘 삭제 -만약 당신이 알고리즘들을 삭제하기 원한다면, 아래 코드로 간단하게 실행할 수 있습니다: - - $ pip3 uninstall -y algorithms - -## 구현 알고리즘 목록 - -- [arrays : 배열](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) -- [backtrack : 백트래킹](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs : 너비 우선 탐색](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit : 비트](algorithms/bit) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_ones](algorithms/bit/count_ones.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [find_difference](algorithms/bit/find_difference.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) -- [calculator : 계산기](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) -- [dfs : 깊이 우선 탐색](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [dp : 동적 계획법](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) -- [graph : 그래프](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) -- [heap : 힙](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) -- [iterable : 반복 가능한 것](algorithms/iterables) - - [convolved](algorithms/iterables/convolved.py) -- [linkedlist : 연결 리스트](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map : 맵](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) -- [maths : 수학 계산](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [combination](algorithms/maths/combination.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) -- [matrix : 행렬](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py -- [queues : 큐](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search : 탐색 알고리즘](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurance](algorithms/search/first_occurance.py) - - [last_occurance](algorithms/search/last_occurance.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) -- [set : 집합](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) -- [sort : 정렬 알고리즘](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack : 스택](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [strings : 문자열](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) -- [tree : 트리](algorithms/tree) - - [bst : 이진 탐색 트리](algorithms/tree/tree/bst) - - [array2bst](algorithms/tree/bst/array2bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [red_black_tree : 레드 블랙 트리](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree : 세그먼트 트리](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [traversal : 트리 순회](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie : 트라이](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bintree2list](algorithms/tree/bintree2list.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [union-find : 합집합 찾기](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) - -## 기여자들 -이 저장소는 아래 사람들에 의해 유지되고 있습니다. - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -그리고 이 저장소를 만드는데 도움을 준 [모든 기여자](https://github.com/keon/algorithms/graphs/contributors) -분 들에게 감사를 표합니다. diff --git a/README_PTBR.md b/README_PTBR.md deleted file mode 100644 index c8bed5417..000000000 --- a/README_PTBR.md +++ /dev/null @@ -1,363 +0,0 @@ -

- -[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português | [Français](README_FR.md) | [Español](README_ES.md) - -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -Estruturas de Dados e Algoritmos Pythonicos -========================================= - -Exemplos de implementações mínimas e limpas de estruturas de dados e algoritmos em Python 3. - -## Contribuir -Obrigado pelo seu interesse em contribuir! Há muitas maneiras de contribuir para este projeto. [Comece aqui](CONTRIBUTING.md) - -## Testes - -### Usando unittest -Para executar todos os testes, digite: - - $ python3 -m unittest discover tests - -Para executar algum teste específico, você pode fazer isso da seguinte maneira (Ex.: sort): - - $ python3 -m unittest tests.test_sort - -### Usando pytest -Para executar todos os testes, digite: - - $ python3 -m pytest tests - -## Instalar -Se você quiser usar os algoritmos da API em seu código, é tão simples quanto: - - $ pip3 install algorithms - -Você pode testar criando um arquivo python: (Ex.: usando `merge_sort` em `sort`) - -```python3 -from algorithms.sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort(my_list) - print(my_list) -``` - -## Desinstalar -Se você deseja desinstalar os algoritmos, é tão simples quanto: - - $ pip3 uninstall -y algorithms - -## Lista de Implementações - -- [arrays](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) -- [backtrack](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [expression_add_operators](algorithms/backtrack/expression_add_operators.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit](algorithms/bit) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [count_ones](algorithms/bit/count_ones.py) - - [find_difference](algorithms/bit/find_difference.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) -- [calculator](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) -- [dfs](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [dp](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) -- [graph](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/checkDiGraphStronglyConnected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) -- [heap](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) -- [iterables](algorithms/iterables) - - [convolved](algorithms/iterables/convolved.py) -- [linkedlist](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) -- [maths](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [combination](algorithms/maths/combination.py) - - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) -- [matrix](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py -- [queues](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurance](algorithms/search/first_occurance.py) - - [last_occurance](algorithms/search/last_occurance.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) -- [set](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) -- [sort](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [strings](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring_characters](algorithms/strings/delete_reoccurring_characters.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [unique_morse](algorithms/strings/unique_morse.py) - - [judge_circle](algorithms/strings/judge_circle.py) - - [strong_password](algorithms/strings/strong_password.py) - - [caesar_cipher](algorithms/strings/caesar_cipher.py) - - [contain_string](algorithms/strings/contain_string.py) - - [count_binary_substring](algorithms/strings/count_binary_substring.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) -- [tree](algorithms/tree) - - [bst](algorithms/tree/tree/bst) - - [array2bst](algorithms/tree/bst/array2bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [red_black_tree](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [traversal](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bintree2list](algorithms/tree/bintree2list.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [unix](algorithms/unix) - - [path](algorithms/unix/path/) - - [join_with_slash](algorithms/unix/path/join_with_slash.py) - - [full_path](algorithms/unix/path/full_path.py) - - [split](algorithms/unix/path/split.py) -- [union-find](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) - -## Contribuidores -O repositório é mantido por - -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -Obrigado a [todos os contribuidores](https://github.com/keon/algorithms/graphs/contributors) -que ajudaram na construção do repositório. From ec4d1363fe89ddc5dd5b53fc9b9a4cd8e537c612 Mon Sep 17 00:00:00 2001 From: keon Date: Sat, 30 Mar 2019 05:51:24 -0700 Subject: [PATCH 148/302] format readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 229114e0f..e56cd4cab 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -

- [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) [![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) [![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) +

+ Pythonic Data Structures and Algorithms ========================================= From 638b43caae6bf40954dcce4d7d8c271105ae8b79 Mon Sep 17 00:00:00 2001 From: keon Date: Sat, 30 Mar 2019 05:52:44 -0700 Subject: [PATCH 149/302] simplify contributor list --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index e56cd4cab..e279953b8 100644 --- a/README.md +++ b/README.md @@ -368,14 +368,6 @@ If you want to uninstall algorithms, it is as simple as: - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) ## Contributors -The repo is maintained by -* [Keon Kim](https://github.com/keon) -* [Rahul Goswami](https://github.com/goswami-rahul) -* [Christian Bender](https://github.com/christianbender) -* [Ankit Agarwal](https://github.com/ankit167) -* [Hai Hoang Dang](https://github.com/danghai) -* [Saad](https://github.com/SaadBenn) - -And thanks to [all the contributors](https://github.com/keon/algorithms/graphs/contributors) +Thanks to [all the contributors](https://github.com/keon/algorithms/graphs/contributors) who helped in building the repo. From 4d6569464a62a75c1357acc97e2dd32ee2f9f4a3 Mon Sep 17 00:00:00 2001 From: Ray Cao Date: Sun, 28 Apr 2019 20:56:01 -0400 Subject: [PATCH 150/302] Add 7 Matrix Unit Tests and Implement Matrix Multiplication (#497) * add_matrix_multiplication * fix_rotate_image * test_matrix * add_matrix_multiplication * fix_matrix_multiplication * fix test_matrix * fix test_matrix * fix test_matrix --- README.md | 1 + algorithms/matrix/multiply.py | 28 ++++ algorithms/matrix/rotate_image.py | 3 +- algorithms/matrix/sudoku_validator.py | 29 ---- tests/test_matrix.py | 229 ++++++++++++++++++++++++-- 5 files changed, 244 insertions(+), 46 deletions(-) create mode 100644 algorithms/matrix/multiply.py diff --git a/README.md b/README.md index e279953b8..89def9ece 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,7 @@ If you want to uninstall algorithms, it is as simple as: - [copy_transform](algorithms/matrix/copy_transform.py) - [count_paths](algorithms/matrix/count_paths.py) - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [matrix_multiplication](algorithms/matrix/multiply.py) - [rotate_image](algorithms/matrix/rotate_image.py) - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) diff --git a/algorithms/matrix/multiply.py b/algorithms/matrix/multiply.py new file mode 100644 index 000000000..2c1cba8f2 --- /dev/null +++ b/algorithms/matrix/multiply.py @@ -0,0 +1,28 @@ +""" +This algorithm takes two compatible two dimensional matrix +and return their product +Space complexity: O(n^2) +Possible edge case: the number of columns of multiplicand not consistent with +the number of rows of multiplier, will raise exception +""" + + +def multiply(multiplicand: list, multiplier: list) -> list: + """ + :type A: List[List[int]] + :type B: List[List[int]] + :rtype: List[List[int]] + """ + multiplicand_row, multiplicand_col = len( + multiplicand), len(multiplicand[0]) + multiplier_row, multiplier_col = len(multiplier), len(multiplier[0]) + if(multiplicand_col != multiplier_row): + raise Exception( + "Multiplicand matrix not compatible with Multiplier matrix.") + # create a result matrix + result = [[0] * multiplier_col for i in range(multiplicand_row)] + for i in range(multiplicand_row): + for j in range(multiplier_col): + for k in range(len(multiplier)): + result[i][j] += multiplicand[i][k] * multiplier[k][j] + return result diff --git a/algorithms/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py index 21f1c74ee..f237fbf44 100644 --- a/algorithms/matrix/rotate_image.py +++ b/algorithms/matrix/rotate_image.py @@ -14,13 +14,14 @@ # 4 5 6 => 4 5 6 => 8 5 2 # 7 8 9 1 2 3 9 6 3 -def rotate(mat): +def rotate(mat): if not mat: return mat mat.reverse() for i in range(len(mat)): for j in range(i): mat[i][j], mat[j][i] = mat[j][i], mat[i][j] + return mat if __name__ == "__main__": diff --git a/algorithms/matrix/sudoku_validator.py b/algorithms/matrix/sudoku_validator.py index ad2faebeb..7bda6e424 100644 --- a/algorithms/matrix/sudoku_validator.py +++ b/algorithms/matrix/sudoku_validator.py @@ -82,32 +82,3 @@ def valid_solution_set (board): return False return True - -# test cases -# To avoid congestion I'll leave testing all the functions to the reader. Just change the name of the function in the below test cases. -import unittest -class TestSuite(unittest.TestCase): - def test_valid(self): - self.assertTrue(valid_solution([[5, 3, 4, 6, 7, 8, 9, 1, 2], - [6, 7, 2, 1, 9, 5, 3, 4, 8], - [1, 9, 8, 3, 4, 2, 5, 6, 7], - [8, 5, 9, 7, 6, 1, 4, 2, 3], - [4, 2, 6, 8, 5, 3, 7, 9, 1], - [7, 1, 3, 9, 2, 4, 8, 5, 6], - [9, 6, 1, 5, 3, 7, 2, 8, 4], - [2, 8, 7, 4, 1, 9, 6, 3, 5], - [3, 4, 5, 2, 8, 6, 1, 7, 9]])) - - def test_invalid(self): - self.assertFalse(valid_solution([[5, 3, 4, 6, 7, 8, 9, 1, 2], - [6, 7, 2, 1, 9, 0, 3, 4, 9], - [1, 0, 0, 3, 4, 2, 5, 6, 0], - [8, 5, 9, 7, 6, 1, 0, 2, 0], - [4, 2, 6, 8, 5, 3, 7, 9, 1], - [7, 1, 3, 9, 2, 4, 8, 5, 6], - [9, 0, 1, 5, 3, 7, 2, 1, 4], - [2, 8, 7, 4, 1, 9, 6, 3, 5], - [3, 0, 0, 4, 8, 1, 1, 7, 9]])) - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 152727a78..4d7e129a6 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -1,34 +1,86 @@ from algorithms.matrix import ( - crout_matrix_decomposition - ) + bomb_enemy, + copy_transform, + crout_matrix_decomposition, + multiply, + rotate_image, + sparse_dot_vector, + spiral_traversal, + sudoku_validator +) +import unittest -import unittest +class TestBombEnemy(unittest.TestCase): + def test_3x4(self): + grid1 = [ + ["0","E","0","0"], + ["E","0","W","E"], + ["0","E","0","0"] + ] + self.assertEqual(3, bomb_enemy.max_killed_enemies(grid1)) + + grid1 = [ + ["0", "E", "0", "E"], + ["E", "E", "E", "0"], + ["E", "0", "W", "E"], + ["0", "E", "0", "0"] + ] + grid2 = [ + ["0", "0", "0", "E"], + ["E", "0", "0", "0"], + ["E", "0", "W", "E"], + ["0", "E", "0", "0"] + ] + self.assertEqual(5, bomb_enemy.max_killed_enemies(grid1)) + self.assertEqual(3, bomb_enemy.max_killed_enemies(grid2)) + + +class TestCopyTransform(unittest.TestCase): + """[summary] + Test for the file copy_transform.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_copy_transform(self): + self.assertEqual(copy_transform.rotate_clockwise( + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + + self.assertEqual(copy_transform.rotate_counterclockwise( + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[3, 6, 9], [2, 5, 8], [1, 4, 7]]) + + self.assertEqual(copy_transform.top_left_invert( + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[1, 4, 7], [2, 5, 8], [3, 6, 9]]) + + self.assertEqual(copy_transform.bottom_left_invert( + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[9, 6, 3], [8, 5, 2], [7, 4, 1]]) class TestCroutMatrixDecomposition(unittest.TestCase): """[summary] - Test for the file crout_matrix_decomposition.crout_matrix_decomposition.py + Test for the file crout_matrix_decomposition.py Arguments: unittest {[type]} -- [description] """ - + def test_crout_matrix_decomposition(self): self.assertEqual(([[9.0, 0.0], [7.0, 0.0]], [[1.0, 1.0], [0.0, 1.0]]), crout_matrix_decomposition.crout_matrix_decomposition( - [[9,9], [7,7]])) - + [[9, 9], [7, 7]])) + self.assertEqual(([[1.0, 0.0, 0.0], [3.0, -2.0, 0.0], [6.0, -5.0, 0.0]], - [[1.0, 2.0, 3.0], - [0.0, 1.0, 2.0], - [0.0, 0.0, 1.0]]), + [[1.0, 2.0, 3.0], + [0.0, 1.0, 2.0], + [0.0, 0.0, 1.0]]), crout_matrix_decomposition.crout_matrix_decomposition( - [[1,2,3],[3,4,5],[6,7,8]])) - + [[1, 2, 3], [3, 4, 5], [6, 7, 8]])) + self.assertEqual(([[2.0, 0, 0, 0], [4.0, -1.0, 0, 0], [6.0, -2.0, 2.0, 0], @@ -38,9 +90,154 @@ def test_crout_matrix_decomposition(self): [0, 0, 1.0, 0.0], [0, 0, 0, 1.0]]), crout_matrix_decomposition.crout_matrix_decomposition( - [[2,1,3,1], [4,1,4,1], [6,1,7,1], [8,1,9,1]])) - - - + [[2, 1, 3, 1], [4, 1, 4, 1], [6, 1, 7, 1], [8, 1, 9, 1]])) + + +class TestMultiply(unittest.TestCase): + """[summary] + Test for the file multiply.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_multiply(self): + self.assertEqual(multiply.multiply( + [[1, 2, 3], [2, 1, 1]], [[1], [2], [3]]), [[14], [7]]) + + +class TestRotateImage(unittest.TestCase): + """[summary] + Test for the file rotate_image.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_rotate_image(self): + self.assertEqual(rotate_image.rotate( + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + + +class TestSparseDotVector(unittest.TestCase): + """[summary] + Test for the file sparse_dot_vector.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_sparse_dot_vector(self): + self.assertEqual(sparse_dot_vector.dot_product(sparse_dot_vector.vector_to_index_value_list( + [1., 2., 3.]), sparse_dot_vector.vector_to_index_value_list([0., 2., 2.])), 10) + + +class TestSpiralTraversal(unittest.TestCase): + """[summary] + Test for the file spiral_traversal.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_spiral_traversal(self): + self.assertEqual(spiral_traversal.spiral_traversal( + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [1, 2, 3, 6, 9, 8, 7, 4, 5]) + + +class TestSudokuValidator(unittest.TestCase): + """[summary] + Test for the file sudoku_validator.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_sudoku_validator(self): + self.assertTrue( + sudoku_validator.valid_solution( + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 5, 3, 4, 8], + [1, 9, 8, 3, 4, 2, 5, 6, 7], + [8, 5, 9, 7, 6, 1, 4, 2, 3], + [4, 2, 6, 8, 5, 3, 7, 9, 1], + [7, 1, 3, 9, 2, 4, 8, 5, 6], + [9, 6, 1, 5, 3, 7, 2, 8, 4], + [2, 8, 7, 4, 1, 9, 6, 3, 5], + [3, 4, 5, 2, 8, 6, 1, 7, 9] + ])) + + self.assertTrue( + sudoku_validator.valid_solution_hashtable( + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 5, 3, 4, 8], + [1, 9, 8, 3, 4, 2, 5, 6, 7], + [8, 5, 9, 7, 6, 1, 4, 2, 3], + [4, 2, 6, 8, 5, 3, 7, 9, 1], + [7, 1, 3, 9, 2, 4, 8, 5, 6], + [9, 6, 1, 5, 3, 7, 2, 8, 4], + [2, 8, 7, 4, 1, 9, 6, 3, 5], + [3, 4, 5, 2, 8, 6, 1, 7, 9] + ])) + + self.assertTrue( + sudoku_validator.valid_solution_set( + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 5, 3, 4, 8], + [1, 9, 8, 3, 4, 2, 5, 6, 7], + [8, 5, 9, 7, 6, 1, 4, 2, 3], + [4, 2, 6, 8, 5, 3, 7, 9, 1], + [7, 1, 3, 9, 2, 4, 8, 5, 6], + [9, 6, 1, 5, 3, 7, 2, 8, 4], + [2, 8, 7, 4, 1, 9, 6, 3, 5], + [3, 4, 5, 2, 8, 6, 1, 7, 9] + ])) + + self.assertFalse( + sudoku_validator.valid_solution( + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 0, 3, 4, 9], + [1, 0, 0, 3, 4, 2, 5, 6, 0], + [8, 5, 9, 7, 6, 1, 0, 2, 0], + [4, 2, 6, 8, 5, 3, 7, 9, 1], + [7, 1, 3, 9, 2, 4, 8, 5, 6], + [9, 0, 1, 5, 3, 7, 2, 1, 4], + [2, 8, 7, 4, 1, 9, 6, 3, 5], + [3, 0, 0, 4, 8, 1, 1, 7, 9] + ])) + + self.assertFalse( + sudoku_validator.valid_solution_hashtable( + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 0, 3, 4, 9], + [1, 0, 0, 3, 4, 2, 5, 6, 0], + [8, 5, 9, 7, 6, 1, 0, 2, 0], + [4, 2, 6, 8, 5, 3, 7, 9, 1], + [7, 1, 3, 9, 2, 4, 8, 5, 6], + [9, 0, 1, 5, 3, 7, 2, 1, 4], + [2, 8, 7, 4, 1, 9, 6, 3, 5], + [3, 0, 0, 4, 8, 1, 1, 7, 9] + ])) + + self.assertFalse( + sudoku_validator.valid_solution_set( + [ + [5, 3, 4, 6, 7, 8, 9, 1, 2], + [6, 7, 2, 1, 9, 0, 3, 4, 9], + [1, 0, 0, 3, 4, 2, 5, 6, 0], + [8, 5, 9, 7, 6, 1, 0, 2, 0], + [4, 2, 6, 8, 5, 3, 7, 9, 1], + [7, 1, 3, 9, 2, 4, 8, 5, 6], + [9, 0, 1, 5, 3, 7, 2, 1, 4], + [2, 8, 7, 4, 1, 9, 6, 3, 5], + [3, 0, 0, 4, 8, 1, 1, 7, 9] + ])) + + if __name__ == "__main__": unittest.main() From 47f6013dd1fad4459f394f95c97ecb9ae4bb9e55 Mon Sep 17 00:00:00 2001 From: Patryk Date: Thu, 2 May 2019 07:31:03 +0200 Subject: [PATCH 151/302] Add huffman coding (encode and decode file), add tests for huffman coding (#500) --- README.md | 2 + algorithms/compression/__init__.py | 0 algorithms/compression/huffman_coding.py | 328 +++++++++++++++++++++++ tests/test_compression.py | 38 +++ 4 files changed, 368 insertions(+) create mode 100644 algorithms/compression/__init__.py create mode 100644 algorithms/compression/huffman_coding.py create mode 100644 tests/test_compression.py diff --git a/README.md b/README.md index 89def9ece..a5c6d9706 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,8 @@ If you want to uninstall algorithms, it is as simple as: - [binary_gap](algorithms/bit/binary_gap.py) - [calculator](algorithms/calculator) - [math_parser](algorithms/calculator/math_parser.py) +- [compression](algorithms/compression) + - [huffman_coding](algorithms/compression/huffman_coding.py) - [dfs](algorithms/dfs) - [all_factors](algorithms/dfs/all_factors.py) - [count_islands](algorithms/dfs/count_islands.py) diff --git a/algorithms/compression/__init__.py b/algorithms/compression/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/algorithms/compression/huffman_coding.py b/algorithms/compression/huffman_coding.py new file mode 100644 index 000000000..44effb19c --- /dev/null +++ b/algorithms/compression/huffman_coding.py @@ -0,0 +1,328 @@ +""" +Huffman coding is an efficient method of compressing data without losing information. +This algorithm analyzes the symbols that appear in a message. +Symbols that appear more often will be encoded as a shorter-bit string +while symbols that aren't used as much will be encoded as longer strings. +""" + +from collections import defaultdict, deque +import heapq + + +class Node: + def __init__(self, frequency=0, sign=None, left=None, right=None): + self.frequency = frequency + self.sign = sign + self.left = left + self.right = right + + def __lt__(self, other): + return self.frequency < other.frequency + + def __gt__(self, other): + return self.frequency > other.frequency + + def __eq__(self, other): + return self.frequency == other.frequency + + def __str__(self): + return "".format(self.sign, self.frequency) + + def __repr__(self): + return "".format(self.sign, self.frequency) + + +class HuffmanReader: + def __init__(self, file): + self.file = file + self.buffer = [] + self.is_last_byte = False + + def get_number_of_additional_bits_in_the_last_byte(self) -> int: + bin_num = self.get_bit() + self.get_bit() + self.get_bit() + return int(bin_num, 2) + + def load_tree(self) -> Node: + """ + Load tree from file + + :return: + """ + node_stack = deque() + queue_leaves = deque() + root = Node() + + current_node = root + is_end_of_tree = False + while not is_end_of_tree: + current_bit = self.get_bit() + if current_bit == "0": + current_node.left = Node() + current_node.right = Node() + node_stack.append(current_node.right) # going to left node, right push on stack + current_node = current_node.left + else: + queue_leaves.append(current_node) + if node_stack: + current_node = node_stack.pop() + else: + is_end_of_tree = True + + self._fill_tree(queue_leaves) + + return root + + def _fill_tree(self, leaves_queue): + """ + Load values to tree after reading tree + :param leaves_queue: + :return: + """ + leaves_queue.reverse() + while leaves_queue: + node = leaves_queue.pop() + s = int(self.get_byte(), 2) + node.sign = s + + def _load_byte(self, buff_limit=8) -> bool: + """ + Load next byte is buffer is less than buff_limit + :param buff_limit: + :return: True if there is enough bits in buffer to read + """ + if len(self.buffer) <= buff_limit: + byte = self.file.read(1) + + if not byte: + return False + + i = int.from_bytes(byte, "big") + self.buffer.extend(list("{0:08b}".format(i))) + + return True + + def get_bit(self, buff_limit=8): + if self._load_byte(buff_limit): + bit = self.buffer.pop(0) + return bit + else: + return -1 + + def get_byte(self): + if self._load_byte(): + byte_list = self.buffer[:8] + self.buffer = self.buffer[8:] + + return "".join(byte_list) + else: + return -1 + + +class HuffmanWriter: + def __init__(self, file): + self.file = file + self.buffer = "" + self.saved_bits = 0 + + def write_char(self, char): + self.write_int(ord(char)) + + def write_int(self, num): + bin_int = "{0:08b}".format(num) + self.write_bits(bin_int) + + def write_bits(self, bits): + self.saved_bits += len(bits) + + self.buffer += bits + + while len(self.buffer) >= 8: + i = int(self.buffer[:8], 2) + self.file.write(bytes([i])) + self.buffer = self.buffer[8:] + + def save_tree(self, tree): + """ + Generate and save tree code to file + :param tree: + :return: + """ + signs = [] + tree_code = "" + + def get_code_tree(T): + nonlocal tree_code + if T.sign is not None: + signs.append(T.sign) + if T.left: + tree_code += "0" + get_code_tree(T.left) + if T.right: + tree_code += "1" + get_code_tree(T.right) + + get_code_tree(tree) + self.write_bits(tree_code + "1") # "1" indicates that tree ended (it will be needed to load the tree) + for int_sign in signs: + self.write_int(int_sign) + + def _save_information_about_additional_bits(self, additional_bits: int): + """ + Overwrite first three bits in the file + :param additional_bits: number of bits that were appended to fill last byte + :return: + """ + self.file.seek(0) + first_byte_raw = self.file.read(1) + self.file.seek(0) + first_byte = "{0:08b}".format(int.from_bytes(first_byte_raw, "big")) + # overwrite first three bits + first_byte = first_byte[3:] + first_byte = "{0:03b}".format(additional_bits) + first_byte + + self.write_bits(first_byte) + + def close(self): + additional_bits = 8 - len(self.buffer) + if additional_bits != 8: # buffer is empty, no need to append extra "0" + self.write_bits("0" * additional_bits) + self._save_information_about_additional_bits(additional_bits) + + +class TreeFinder: + """ + Class to help find signs in tree + """ + + def __init__(self, tree): + self.root = tree + self.current_node = tree + self.found = None + + def find(self, bit): + """ + Find sign in tree + :param bit: + :return: True if sign is found + """ + if bit == "0": + self.current_node = self.current_node.left + elif bit == "1": + self.current_node = self.current_node.right + else: + self._reset() + return True + + if self.current_node.sign is not None: + self._reset(self.current_node.sign) + return True + else: + return False + + def _reset(self, found=""): + self.found = found + self.current_node = self.root + + +class HuffmanCoding: + def __init__(self): + pass + + @staticmethod + def decode_file(file_in_name, file_out_name): + with open(file_in_name, "rb") as file_in, open(file_out_name, "wb") as file_out: + reader = HuffmanReader(file_in) + additional_bits = reader.get_number_of_additional_bits_in_the_last_byte() + tree = reader.load_tree() + + HuffmanCoding._decode_and_write_signs_to_file(file_out, reader, tree, additional_bits) + + print("File decoded.") + + @staticmethod + def _decode_and_write_signs_to_file(file, reader: HuffmanReader, tree: Node, additional_bits: int): + tree_finder = TreeFinder(tree) + is_end_of_file = False + + while not is_end_of_file: + bit = reader.get_bit() + if bit != -1: + while not tree_finder.find(bit): # read whole code + bit = reader.get_bit(0) + file.write(bytes([tree_finder.found])) + else: # There is last byte in buffer to parse + is_end_of_file = True + last_byte = reader.buffer + last_byte = last_byte[:-additional_bits] # remove additional "0" used to fill byte + for bit in last_byte: + if tree_finder.find(bit): + file.write(bytes([tree_finder.found])) + + @staticmethod + def encode_file(file_in_name, file_out_name): + with open(file_in_name, "rb") as file_in, open(file_out_name, mode="wb+") as file_out: + signs_frequency = HuffmanCoding._get_char_frequency(file_in) + file_in.seek(0) + tree = HuffmanCoding._create_tree(signs_frequency) + codes = HuffmanCoding._generate_codes(tree) + + writer = HuffmanWriter(file_out) + writer.write_bits("000") # leave space to save how many bits will be appended to fill the last byte + writer.save_tree(tree) + HuffmanCoding._encode_and_write_signs_to_file(file_in, writer, codes) + writer.close() + + print("File encoded.") + + @staticmethod + def _encode_and_write_signs_to_file(file, writer: HuffmanWriter, codes: dict): + sign = file.read(1) + while sign: + int_char = int.from_bytes(sign, "big") + writer.write_bits(codes[int_char]) + sign = file.read(1) + + @staticmethod + def _get_char_frequency(file) -> dict: + is_end_of_file = False + signs_frequency = defaultdict(lambda: 0) + while not is_end_of_file: + prev_pos = file.tell() + sign = file.read(1) + curr_pos = file.tell() + if prev_pos == curr_pos: + is_end_of_file = True + else: + signs_frequency[int.from_bytes(sign, "big")] += 1 + + return signs_frequency + + @staticmethod + def _generate_codes(tree: Node) -> dict: + codes = dict() + HuffmanCoding._go_through_tree_and_create_codes(tree, "", codes) + return codes + + @staticmethod + def _create_tree(signs_frequency: dict) -> Node: + nodes = [Node(frequency=frequency, sign=char_int) for char_int, frequency in signs_frequency.items()] + heapq.heapify(nodes) + + while len(nodes) > 1: + left = heapq.heappop(nodes) + right = heapq.heappop(nodes) + new_node = Node(frequency=left.frequency + right.frequency, left=left, right=right) + heapq.heappush(nodes, new_node) + + return nodes[0] # root + + @staticmethod + def _go_through_tree_and_create_codes(tree: Node, code: str, dict_codes: dict): + if tree.sign is not None: + dict_codes[tree.sign] = code + + if tree.left: + HuffmanCoding._go_through_tree_and_create_codes(tree.left, code + "0", dict_codes) + + if tree.right: + HuffmanCoding._go_through_tree_and_create_codes(tree.right, code + "1", dict_codes) diff --git a/tests/test_compression.py b/tests/test_compression.py new file mode 100644 index 000000000..611886be6 --- /dev/null +++ b/tests/test_compression.py @@ -0,0 +1,38 @@ +from algorithms.compression.huffman_coding import HuffmanCoding + +import unittest + + +class TestHuffmanCoding(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.file_in_name = "huffman_coding_in.txt" + cls.file_out_bin_name = "huffman_coding_out.bin" + cls.file_out_name = "huffman_coding_out.txt" + + def setUp(self): + import random + random.seed(1951) + with open(self.file_in_name, "wb") as file_in: + for i in range(10000): + file_in.write(bytes([random.randrange(0, 256)])) + + def test_huffman_coding(self): + HuffmanCoding.encode_file(self.file_in_name, self.file_out_bin_name) + HuffmanCoding.decode_file(self.file_out_bin_name, self.file_out_name) + + with open(self.file_in_name, "rb") as file_1, open(self.file_out_name, "rb") as file_2: + content_1 = file_1.read() + content_2 = file_2.read() + + self.assertEqual(content_1, content_2) + + def tearDown(self): + import os + os.remove(self.file_in_name) + os.remove(self.file_out_bin_name) + os.remove(self.file_out_name) + + +if __name__ == "__main__": + unittest.main() From 17d72755c15eaeb1171d5dfc4366d7f14dffc706 Mon Sep 17 00:00:00 2001 From: Patryk Date: Thu, 2 May 2019 07:31:16 +0200 Subject: [PATCH 152/302] Add b-tree (#501) * Add huffman coding (encode and decode file), add tests for huffman coding * Add b-tree algorithm (insertion and deletion), add tests for b-tree --- README.md | 1 + algorithms/tree/b_tree.py | 235 ++++++++++++++++++++++++++++++++++++++ tests/test_tree.py | 58 ++++++++++ 3 files changed, 294 insertions(+) create mode 100644 algorithms/tree/b_tree.py diff --git a/README.md b/README.md index a5c6d9706..d2578e3cf 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ If you want to uninstall algorithms, it is as simple as: - [trie](algorithms/tree/trie) - [add_and_search](algorithms/tree/trie/add_and_search.py) - [trie](algorithms/tree/trie/trie.py) + - [b_tree](algorithms/tree/b_tree.py) - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) - [deepest_left](algorithms/tree/deepest_left.py) diff --git a/algorithms/tree/b_tree.py b/algorithms/tree/b_tree.py new file mode 100644 index 000000000..bedf31b6a --- /dev/null +++ b/algorithms/tree/b_tree.py @@ -0,0 +1,235 @@ +""" +B-tree is used to disk operations. Each node (except root) contains +at least t-1 keys (t children) and at most 2*t - 1 keys (2*t children) +where t is the degree of b-tree. It is not a kind of typical bst tree, because +this tree grows up. +B-tree is balanced which means that the difference between height of left subtree and right subtree is at most 1. + +Complexity + n - number of elements + t - degree of tree + Tree always has height at most logt (n+1)/2 + Algorithm Average Worst case + Space O(n) O(n) + Search O(log n) O(log n) + Insert O(log n) O(log n) + Delete O(log n) O(log n) +""" + + +class Node: + def __init__(self): + # self.is_leaf = is_leaf + self.keys = [] + self.children = [] + + def __repr__(self): + return "".format(self.keys) + + @property + def is_leaf(self): + return len(self.children) == 0 + + +class BTree: + def __init__(self, t=2): + self.min_numbers_of_keys = t - 1 + self.max_number_of_keys = 2 * t - 1 + + self.root = Node() + + def _split_child(self, parent: Node, child_index: int): + new_right_child = Node() + half_max = self.max_number_of_keys // 2 + child = parent.children[child_index] + middle_key = child.keys[half_max] + new_right_child.keys = child.keys[half_max + 1:] + child.keys = child.keys[:half_max] + # child is left child of parent after splitting + + if not child.is_leaf: + new_right_child.children = child.children[half_max + 1:] + child.children = child.children[:half_max + 1] + + parent.keys.insert(child_index, middle_key) + parent.children.insert(child_index + 1, new_right_child) + + def insert_key(self, key): + if len(self.root.keys) >= self.max_number_of_keys: # overflow, tree increases in height + new_root = Node() + new_root.children.append(self.root) + self.root = new_root + self._split_child(new_root, 0) + self._insert_to_nonfull_node(self.root, key) + else: + self._insert_to_nonfull_node(self.root, key) + + def _insert_to_nonfull_node(self, node: Node, key): + i = len(node.keys) - 1 + while i >= 0 and node.keys[i] >= key: # find position where insert key + i -= 1 + + if node.is_leaf: + node.keys.insert(i + 1, key) + else: + if len(node.children[i + 1].keys) >= self.max_number_of_keys: # overflow + self._split_child(node, i + 1) + if node.keys[i + 1] < key: # decide which child is going to have a new key + i += 1 + + self._insert_to_nonfull_node(node.children[i + 1], key) + + def find(self, key) -> bool: + current_node = self.root + while True: + i = len(current_node.keys) - 1 + while i >= 0 and current_node.keys[i] > key: + i -= 1 + + if i >= 0 and current_node.keys[i] == key: + return True + elif current_node.is_leaf: + return False + else: + current_node = current_node.children[i + 1] + + def remove_key(self, key): + self._remove_key(self.root, key) + + def _remove_key(self, node: Node, key) -> bool: + try: + key_index = node.keys.index(key) + if node.is_leaf: + node.keys.remove(key) + return True + else: + self._remove_from_nonleaf_node(node, key_index) + + return True + + except ValueError: # key not found in node + if node.is_leaf: + print("Key not found.") + return False # key not found + else: + i = 0 + number_of_keys = len(node.keys) + while i < number_of_keys and key > node.keys[i]: # decide in which subtree may be key + i += 1 + + action_performed = self._repair_tree(node, i) + if action_performed: + return self._remove_key(node, key) + else: + return self._remove_key(node.children[i], key) + + def _repair_tree(self, node: Node, child_index: int) -> bool: + child = node.children[child_index] + if self.min_numbers_of_keys < len(child.keys) <= self.max_number_of_keys: # The leaf/node is correct + return False + + if child_index > 0 and len(node.children[child_index - 1].keys) > self.min_numbers_of_keys: + self._rotate_right(node, child_index) + return True + + if (child_index < len(node.children) - 1 and + len(node.children[child_index + 1].keys) > self.min_numbers_of_keys): # 0 <-- 1 + self._rotate_left(node, child_index) + return True + + if child_index > 0: + # merge child with brother on the left + self._merge(node, child_index - 1, child_index) + else: + # merge child with brother on the right + self._merge(node, child_index, child_index + 1) + + return True + + def _rotate_left(self, parent_node: Node, child_index: int): + """ + Take key from right brother of the child and transfer to the child + """ + new_child_key = parent_node.keys[child_index] + new_parent_key = parent_node.children[child_index + 1].keys.pop(0) + parent_node.children[child_index].keys.append(new_child_key) + parent_node.keys[child_index] = new_parent_key + + if not parent_node.children[child_index + 1].is_leaf: + ownerless_child = parent_node.children[child_index + 1].children.pop(0) + # make ownerless_child as a new biggest child (with highest key) -> transfer from right subtree to left subtree + parent_node.children[child_index].children.append(ownerless_child) + + def _rotate_right(self, parent_node: Node, child_index: int): + """ + Take key from left brother of the child and transfer to the child + """ + parent_key = parent_node.keys[child_index - 1] + new_parent_key = parent_node.children[child_index - 1].keys.pop() + parent_node.children[child_index].keys.insert(0, parent_key) + parent_node.keys[child_index - 1] = new_parent_key + + if not parent_node.children[child_index - 1].is_leaf: + ownerless_child = parent_node.children[child_index - 1].children.pop() + # make ownerless_child as a new lowest child (with lowest key) -> transfer from left subtree to right subtree + parent_node.children[child_index].children.insert(0, ownerless_child) + + def _merge(self, parent_node: Node, to_merge_index: int, transfered_child_index: int): + from_merge_node = parent_node.children.pop(transfered_child_index) + parent_key_to_merge = parent_node.keys.pop(to_merge_index) + to_merge_node = parent_node.children[to_merge_index] + to_merge_node.keys.append(parent_key_to_merge) + to_merge_node.keys.extend(from_merge_node.keys) + + if not to_merge_node.is_leaf: + to_merge_node.children.extend(from_merge_node.children) + + if parent_node == self.root and not parent_node.keys: + self.root = to_merge_node + + def _remove_from_nonleaf_node(self, node: Node, key_index: int): + key = node.keys[key_index] + left_subtree = node.children[key_index] + if len(left_subtree.keys) > self.min_numbers_of_keys: + largest_key = self._find_largest_and_delete_in_left_subtree(left_subtree) + elif len(node.children[key_index + 1].keys) > self.min_numbers_of_keys: + largest_key = self._find_largest_and_delete_in_right_subtree(node.children[key_index + 1]) + else: + self._merge(node, key_index, key_index + 1) + return self._remove_key(node, key) + + node.keys[key_index] = largest_key + + def _find_largest_and_delete_in_left_subtree(self, node: Node): + if node.is_leaf: + return node.keys.pop() + else: + ch_index = len(node.children) - 1 + self._repair_tree(node, ch_index) + largest_key_in_subtree = self._find_largest_and_delete_in_left_subtree( + node.children[len(node.children) - 1]) + # self._repair_tree(node, ch_index) + return largest_key_in_subtree + + def _find_largest_and_delete_in_right_subtree(self, node: Node): + if node.is_leaf: + return node.keys.pop(0) + else: + ch_index = 0 + self._repair_tree(node, ch_index) + largest_key_in_subtree = self._find_largest_and_delete_in_right_subtree(node.children[0]) + # self._repair_tree(node, ch_index) + return largest_key_in_subtree + + def traverse_tree(self): + self._traverse_tree(self.root) + print() + + def _traverse_tree(self, node: Node): + if node.is_leaf: + print(node.keys, end=" ") + else: + for i, key in enumerate(node.keys): + self._traverse_tree(node.children[i]) + print(key, end=" ") + self._traverse_tree(node.children[-1]) diff --git a/tests/test_tree.py b/tests/test_tree.py index 1fbcd6a2e..912496f8a 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -6,6 +6,7 @@ inorder, inorder_rec ) +from algorithms.tree.b_tree import BTree import unittest @@ -50,5 +51,62 @@ def create_tree(): return n1 +class TestBTree(unittest.TestCase): + + @classmethod + def setUpClass(cls): + import random + random.seed(18719) + cls.random = random + cls.range = 10000 + + def setUp(self): + self.keys_to_insert = [self.random.randrange(-self.range, self.range) for i in range(self.range)] + + def test_insertion_and_find_even_degree(self): + btree = BTree(4) + for i in self.keys_to_insert: + btree.insert_key(i) + + for i in range(100): + key = self.random.choice(self.keys_to_insert) + self.assertTrue(btree.find(key)) + + def test_insertion_and_find_odd_degree(self): + btree = BTree(3) + for i in self.keys_to_insert: + btree.insert_key(i) + + for i in range(100): + key = self.random.choice(self.keys_to_insert) + self.assertTrue(btree.find(key)) + + def test_deletion_even_degree(self): + btree = BTree(4) + key_list = set(self.keys_to_insert) + for i in key_list: + btree.insert_key(i) + + for key in key_list: + btree.remove_key(key) + self.assertFalse(btree.find(key)) + + self.assertEqual(btree.root.keys, []) + self.assertEqual(btree.root.children, []) + + def test_deletion_odd_degree(self): + btree = BTree(3) + key_list = set(self.keys_to_insert) + for i in key_list: + btree.insert_key(i) + + for key in key_list: + btree.remove_key(key) + self.assertFalse(btree.find(key)) + + self.assertEqual(btree.root.keys, []) + self.assertEqual(btree.root.children, []) + + if __name__ == '__main__': unittest.main() From f3a4512fc056175612ad4bfb13240743591d3830 Mon Sep 17 00:00:00 2001 From: everfight Date: Fri, 3 May 2019 18:47:04 +0800 Subject: [PATCH 153/302] Update limit.py (#498) * Update limit.py boundary * Update limit.py 1. replace == with is 2. remove spaces around = --- algorithms/arrays/limit.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py index 131d16edb..75c13d574 100644 --- a/algorithms/arrays/limit.py +++ b/algorithms/arrays/limit.py @@ -13,19 +13,20 @@ """ # tl:dr -- array slicing by value -def limit(arr, min_lim = None, max_lim = None): +def limit(arr, min_lim=None, max_lim=None): result = [] - if min_lim == None: + if min_lim is None and max_lim: for i in arr: if i <= max_lim: result.append(i) - elif max_lim == None: + elif max_lim is None and min_lim: for i in arr: if i >= min_lim: result.append(i) - else: + elif max_lim and min_lim: for i in arr: if i >= min_lim and i <= max_lim: result.append(i) - + else: + result = arr return result From 95ad7b225a31cc3e123c9e3982b2f833e6ac5a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=86=AC=E5=86=AC?= Date: Fri, 17 May 2019 17:57:09 +0800 Subject: [PATCH 154/302] Update limit.py (#502) * Update limit.py * Update limit.py --- algorithms/arrays/limit.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py index 75c13d574..33468a06b 100644 --- a/algorithms/arrays/limit.py +++ b/algorithms/arrays/limit.py @@ -14,19 +14,10 @@ # tl:dr -- array slicing by value def limit(arr, min_lim=None, max_lim=None): - result = [] - if min_lim is None and max_lim: - for i in arr: - if i <= max_lim: - result.append(i) - elif max_lim is None and min_lim: - for i in arr: - if i >= min_lim: - result.append(i) - elif max_lim and min_lim: - for i in arr: - if i >= min_lim and i <= max_lim: - result.append(i) - else: - result = arr - return result + if min_lim is None and max_lim is not None: + return [x for x in arr if x <= max_lim] + if max_lim is None and min_lim is not None: + return [x for x in arr if x >= min_lim] + if max_lim is not None and min_lim is not None: + return [x for x in arr if min_lim <= x <= max_lim] + return arr From 68c2661ab7d3c8567a97263170f8abddc2a56da4 Mon Sep 17 00:00:00 2001 From: Keon Date: Tue, 21 May 2019 08:58:22 -0700 Subject: [PATCH 155/302] Delete tree.md --- tree.md | 303 -------------------------------------------------------- 1 file changed, 303 deletions(-) delete mode 100644 tree.md diff --git a/tree.md b/tree.md deleted file mode 100644 index 8fe302f19..000000000 --- a/tree.md +++ /dev/null @@ -1,303 +0,0 @@ -``` - -algorithms -├── arrays -│   ├── delete_nth.py -│   ├── flatten.py -│   ├── garage.py -│   ├── __init__.py -│   ├── josephus.py -│   ├── longest_non_repeat.py -│   ├── max_ones_index.py -│   ├── merge_intervals.py -│   ├── missing_ranges.py -│   ├── move_zeros.py -│   ├── plus_one.py -│   ├── rotate.py -│   ├── summarize_ranges.py -│   ├── three_sum.py -│   └── two_sum.py -├── backtrack -│   ├── add_operators.py -│   ├── anagram.py -│   ├── array_sum_combinations.py -│   ├── combination_sum.py -│   ├── factor_combinations.py -│   ├── find_words.py -│   ├── generate_abbreviations.py -│   ├── generate_parenthesis.py -│   ├── __init__.py -│   ├── letter_combination.py -│   ├── palindrome_partitioning.py -│   ├── pattern_match.py -│   ├── permute.py -│   ├── permute_unique.py -│   ├── subsets.py -│   └── subsets_unique.py -├── bfs -│   ├── shortest_distance_from_all_buildings.py -│   └── word_ladder.py -├── bit -│   ├── add_bitwise_operator.py -│   ├── bit_operation.py -│   ├── bytes_int_conversion.py -│   ├── count_flips_to_convert.py -│   ├── count_ones.py -│   ├── find_difference.py -│   ├── find_missing_number.py -│   ├── flip_bit_longest_sequence.py -│   ├── has_alternative_bit.py -│   ├── __init__.py -│   ├── insert_bit.py -│   ├── power_of_two.py -│   ├── remove_bit.py -│   ├── reverse_bits.py -│   ├── single_number2.py -│   ├── single_number3.py -│   ├── single_number.py -│   ├── subsets.py -│   └── swap_pair.py -├── calculator -│   └── math_parser.py -├── dfs -│   ├── all_factors.py -│   ├── count_islands.py -│   ├── pacific_atlantic.py -│   ├── sudoku_solver.py -│   └── walls_and_gates.py -├── dp -│   ├── buy_sell_stock.py -│   ├── climbing_stairs.py -│   ├── coin_change.py -│   ├── combination_sum.py -│   ├── egg_drop.py -│   ├── fib.py -│   ├── house_robber.py -│   ├── job_scheduling.py -│   ├── knapsack.py -│   ├── longest_increasing.py -│   ├── matrix_chain_order.py -│   ├── max_product_subarray.py -│   ├── max_subarray.py -│   ├── min_cost_path.py -│   ├── num_decodings.py -│   ├── regex_matching.py -│   ├── rod_cut.py -│   └── word_break.py -├── graph -│   ├── checkDiGraphStronglyConnected.py -│   ├── clone_graph.py -│   ├── cycle_detection.py -│   ├── dijkstra.py -│   ├── find_all_cliques.py -│   ├── find_path.py -│   ├── graph.py -│   ├── __init__.py -│   ├── markov_chain.py -│   ├── minimum_spanning_tree.py -│   ├── pathBetweenTwoVerticesInDiGraph.py -│   ├── satisfiability.py -│   ├── tarjan.py -│   ├── Transitive_Closure_DFS.py -│   └── traversal.py -├── heap -│   ├── binary_heap.py -│   ├── __init__.py -│   ├── merge_sorted_k_lists.py -│   ├── skyline.py -│   └── sliding_window_max.py -├── __init__.py -├── iterables -│   ├── __init__.py -│   └── convolved.py -├── linkedlist -│   ├── add_two_numbers.py -│   ├── copy_random_pointer.py -│   ├── delete_node.py -│   ├── first_cyclic_node.py -│   ├── __init__.py -│   ├── intersection.py -│   ├── is_cyclic.py -│   ├── is_palindrome.py -│   ├── is_sorted.py -│   ├── kth_to_last.py -│   ├── linkedlist.py -│   ├── merge_two_list.py -│   ├── partition.py -│   ├── remove_duplicates.py -│   ├── remove_range.py -│   ├── reverse.py -│   ├── rotate_list.py -│   └── swap_in_pairs.py -├── map -│   ├── hashtable.py -│   ├── longest_common_subsequence.py -│   ├── randomized_set.py -│   ├── separate_chaining_hashtable.py -│   └── valid_sudoku.py -├── maths -│   ├── base_conversion.py -│   ├── combination.py -│   ├── extended_gcd.py -│   ├── factorial.py -│   ├── gcd.py -│   ├── generate_strobogrammtic.py -│   ├── __init__.py -│   ├── is_strobogrammatic.py -│   ├── next_bigger.py -│   ├── next_perfect_square.py -│   ├── nth_digit.py -│   ├── prime_check.py -│   ├── primes_sieve_of_eratosthenes.py -│   ├── pythagoras.py -│   ├── rabin_miller.py -│   ├── rsa.py -│   ├── sqrt_precision_factor.py -│   └── summing_digits.py -├── matrix -│   ├── bomb_enemy.py -│   ├── copy_transform.py -│   ├── count_paths.py -│   ├── matrix_rotation.txt -│   ├── rotate_image.py -│   ├── search_in_sorted_matrix.py -│   ├── sparse_dot_vector.py -│   ├── sparse_mul.py -│   ├── spiral_traversal.py -│   └── sudoku_validator.py -├── queues -│   ├── __init__.py -│   ├── max_sliding_window.py -│   ├── moving_average.py -│   ├── priority_queue.py -│   ├── queue.py -│   ├── reconstruct_queue.py -│   └── zigzagiterator.py -├── search -│   ├── binary_search.py -│   ├── find_min_rotate.py -│   ├── first_occurance.py -│   ├── __init__.py -│   ├── jump_search.py -│   ├── last_occurance.py -│   ├── linear_search.py -│   ├── search_insert.py -│   ├── search_range.py -│   ├── search_rotate.py -│   └── two_sum.py -├── set -│   ├── randomized_set.py -│   └── set_covering.py -├── sort -│   ├── bitonic_sort.py -│   ├── bogo_sort.py -│   ├── bubble_sort.py -│   ├── bucket_sort.py -│   ├── cocktail_shaker_sort.py -│   ├── comb_sort.py -│   ├── counting_sort.py -│   ├── gnome_sort.py -│   ├── heap_sort.py -│   ├── __init__.py -│   ├── insertion_sort.py -│   ├── meeting_rooms.py -│   ├── merge_sort.py -│   ├── quick_sort.py -│   ├── radix_sort.py -│   ├── selection_sort.py -│   ├── shell_sort.py -│   ├── sort_colors.py -│   ├── top_sort.py -│   └── wiggle_sort.py -├── stack -│   ├── __init__.py -│   ├── is_consecutive.py -│   ├── is_sorted.py -│   ├── longest_abs_path.py -│   ├── ordered_stack.py -│   ├── remove_min.py -│   ├── simplify_path.py -│   ├── stack.py -│   ├── stutter.py -│   ├── switch_pairs.py -│   └── valid_parenthesis.py -├── strings -│   ├── add_binary.py -│   ├── breaking_bad.py -│   ├── decode_string.py -│   ├── delete_reoccurring.py -│   ├── domain_extractor.py -│   ├── encode_decode.py -│   ├── fizzbuzz.py -│   ├── group_anagrams.py -│   ├── __init__.py -│   ├── int_to_roman.py -│   ├── is_palindrome.py -│   ├── is_rotated.py -│   ├── license_number.py -│   ├── make_sentence.py -│   ├── merge_string_checker.py -│   ├── multiply_strings.py -│   ├── one_edit_distance.py -│   ├── rabin_karp.py -│   ├── reverse_string.py -│   ├── reverse_vowel.py -│   ├── reverse_words.py -│   ├── roman_to_int.py -│   ├── strip_url_params.py -│   ├── validate_coordinates.py -│   └── word_squares.py -├── tree -│   ├── avl -│   │   ├── avl.py -│   │   └── __init__.py -│   ├── binary_tree_paths.py -│   ├── bintree2list.py -│   ├── bst -│   │   ├── array2bst.py -│   │   ├── bst_closest_value.py -│   │   ├── BSTIterator.py -│   │   ├── bst.py -│   │   ├── count_left_node.py -│   │   ├── delete_node.py -│   │   ├── depth_sum.py -│   │   ├── height.py -│   │   ├── is_bst.py -│   │   ├── kth_smallest.py -│   │   ├── lowest_common_ancestor.py -│   │   ├── num_empty.py -│   │   ├── predecessor.py -│   │   ├── serialize_deserialize.py -│   │   ├── successor.py -│   │   └── unique_bst.py -│   ├── deepest_left.py -│   ├── invert_tree.py -│   ├── is_balanced.py -│   ├── is_subtree.py -│   ├── is_symmetric.py -│   ├── longest_consecutive.py -│   ├── lowest_common_ancestor.py -│   ├── max_height.py -│   ├── max_path_sum.py -│   ├── min_height.py -│   ├── path_sum2.py -│   ├── path_sum.py -│   ├── pretty_print.py -│   ├── red_black_tree -│   │   └── red_black_tree.py -│   ├── same_tree.py -│   ├── segment_tree -│   │   └── segment_tree.py -│   ├── traversal -│   │   ├── inorder.py -│   │   ├── level_order.py -│   │   └── zigzag.py -│   ├── tree.py -│   └── trie -│   ├── add_and_search.py -│   └── trie.py -└── union-find - └── count_islands.py - -28 directories, 269 files -``` From a941edcef3eabf1ee97f2bef5a1e62ccfb4c4b75 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 29 Jul 2019 21:22:58 +0200 Subject: [PATCH 156/302] Fix a typo in the pull request template (#514) * Fix a typo in the pull request template * Tox and Travis should use the SAME Python --- PULL_REQUEST_TEMPLATE.md | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 3de1ba41a..ff98cafea 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ - [ ] **If creating a new file :** - [ ] added links to it in the README files ? - [ ] included tests with it ? - - [ ] added description (overview of algorithm, time and space compleixty, and possible edge case) in docstrings ? + - [ ] added description (overview of algorithm, time and space complexity, and possible edge case) in docstrings ? - [ ] **if done some changes :** - [ ] wrote short description in the PR explaining what the changes do ? diff --git a/tox.ini b/tox.ini index b6f350603..5f914e40f 100644 --- a/tox.ini +++ b/tox.ini @@ -43,7 +43,7 @@ commands = [testenv:py36] passenv = CI TRAVIS TRAVIS_* basepython = - python3.4 + python3.6 deps = pytest commands = From 44298eb10322cb73219ed2952ca6b2faa770220d Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 29 Jul 2019 21:38:28 +0200 Subject: [PATCH 157/302] Travis CI: Drop the EOL Python 3.4 and add 3.7 (#513) * Travis CI: Drop the EOL Python 3.4 and add 3.7 * Tox.ini: Travis CI: Drop the EOL py34 --- .travis.yml | 11 ++++++----- tox.ini | 17 ++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9a4450a2..9f2062f64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,17 @@ group: travis_latest +dist: xenial # Travis CI's default distro language: python cache: directories: - $HOME/.cache/pip matrix: include: - - python: 3.4 - env: TOX_ENV=py34 - python: 3.5 - env: TOX_ENV=py35,coverage + env: TOX_ENV=py35 - python: 3.6 env: TOX_ENV=py36 + - python: 3.7 + env: TOX_ENV=py37,coverage install: - pip install -r test_requirements.txt before_script: @@ -20,10 +21,10 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics script: # Check python install package - - pip3 install -e . + - pip install -e . - tox -e $TOX_ENV # Check python uninstall package - - pip3 uninstall -y algorithms + - pip uninstall -y algorithms notifications: on_success: change on_failure: change # `always` will be the setting once code changes slow down diff --git a/tox.ini b/tox.ini index 5f914e40f..f9182236e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,13 @@ [tox] envlist = - py34 py35 py36 + py37 coverage [testenv] passenv = TRAVIS TRAVIS_* basepython = - py34: python3.4 py35: python3.5 py36: python3.6 py37: python3.7 @@ -20,30 +19,30 @@ commands = coverage report -m coveralls -[testenv:py34] +[testenv:py35] passenv = CI TRAVIS TRAVIS_* basepython = - python3.4 + python3.5 deps = pytest commands = python3 -m unittest discover tests python3 -m pytest tests -[testenv:py35] +[testenv:py36] passenv = CI TRAVIS TRAVIS_* basepython = - python3.5 + python3.6 deps = pytest commands = python3 -m unittest discover tests python3 -m pytest tests -[testenv:py36] +[testenv:py37] passenv = CI TRAVIS TRAVIS_* basepython = - python3.6 + python3.7 deps = pytest commands = @@ -54,7 +53,7 @@ commands = passenv = CI TRAVIS TRAVIS_* skip_install = True basepython = - python3.5 + python3.7 commands = coverage run --source=tests,algorithms -m unittest discover tests coverage report -m From 84b1415527ad319964a2f43aa09667e759fd32ae Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 29 Jul 2019 21:48:16 +0200 Subject: [PATCH 158/302] Travis CI: Add more flake8 tests (#512) * Travis CI: Add more flake8 tests * Use ==/!= to compare str, bytes, and int literals Identity is not the same thing as equality in Python. * Use ==/!= to compare str, bytes, and int literals --- .travis.yml | 2 +- algorithms/arrays/move_zeros.py | 2 +- algorithms/tree/red_black_tree/red_black_tree.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f2062f64..1a414e44d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ install: - pip install -r test_requirements.txt before_script: # stop the build if there are Python syntax errors or undefined names - - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics + - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics script: diff --git a/algorithms/arrays/move_zeros.py b/algorithms/arrays/move_zeros.py index b2acd759d..5b50241c4 100644 --- a/algorithms/arrays/move_zeros.py +++ b/algorithms/arrays/move_zeros.py @@ -13,7 +13,7 @@ def move_zeros(array): zeros = 0 for i in array: - if i is 0: # not using `not i` to avoid `False`, `[]`, etc. + if i == 0: # not using `not i` to avoid `False`, `[]`, etc. zeros += 1 else: result.append(i) diff --git a/algorithms/tree/red_black_tree/red_black_tree.py b/algorithms/tree/red_black_tree/red_black_tree.py index 33fb6af4a..6ced71ea6 100644 --- a/algorithms/tree/red_black_tree/red_black_tree.py +++ b/algorithms/tree/red_black_tree/red_black_tree.py @@ -93,10 +93,10 @@ def fix_insert(self, node): return # case 2 the parent color is black, do nothing # case 3 the parent color is red - while node.parent and node.parent.color is 1: + while node.parent and node.parent.color == 1: if node.parent is node.parent.parent.left: uncle_node = node.parent.parent.right - if uncle_node and uncle_node.color is 1: + if uncle_node and uncle_node.color == 1: # case 3.1 the uncle node is red # then set parent and uncle color is black and grandparent is red # then node => node.parent @@ -118,7 +118,7 @@ def fix_insert(self, node): self.right_rotate(node.parent.parent) else: uncle_node = node.parent.parent.left - if uncle_node and uncle_node.color is 1: + if uncle_node and uncle_node.color == 1: # case 3.1 the uncle node is red # then set parent and uncle color is black and grandparent is red # then node => node.parent From 321d492d45fddec06a458af14bc657edc6cab1fa Mon Sep 17 00:00:00 2001 From: KUAN Hsuan-Tso Date: Tue, 30 Jul 2019 03:48:37 +0800 Subject: [PATCH 159/302] fix error if max_number is a multiple of 10 (#511) --- algorithms/sort/radix_sort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/sort/radix_sort.py b/algorithms/sort/radix_sort.py index 89a2dbcc9..52457063c 100644 --- a/algorithms/sort/radix_sort.py +++ b/algorithms/sort/radix_sort.py @@ -10,7 +10,7 @@ def radix_sort(arr, simulation=False): if simulation: print("iteration", iteration, ":", *arr) - while position < max_number: + while position <= max_number: queue_list = [list() for _ in range(10)] for num in arr: From 6f1fc9fadd76cb194183e98cc03587c30d93eb8e Mon Sep 17 00:00:00 2001 From: One-Xiao-Yi <50069454+One-Xiao-Yi@users.noreply.github.com> Date: Thu, 15 Aug 2019 05:18:04 +0800 Subject: [PATCH 160/302] It seems to be wrong in algorithms/bit/binary_gap.py (#518) * It seems to be wrong. * It seems to be wrong. * I haven't read all of them yet, so delete the test section to avoid mistakes in PR. * back * back --- .travis.yml | 2 +- algorithms/arrays/move_zeros.py | 12 ++++++++---- algorithms/bit/binary_gap.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a414e44d..37013bdae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ matrix: - python: 3.6 env: TOX_ENV=py36 - python: 3.7 - env: TOX_ENV=py37,coverage + env: TOX_ENV=py37 install: - pip install -r test_requirements.txt before_script: diff --git a/algorithms/arrays/move_zeros.py b/algorithms/arrays/move_zeros.py index 5b50241c4..606afbfd5 100644 --- a/algorithms/arrays/move_zeros.py +++ b/algorithms/arrays/move_zeros.py @@ -8,15 +8,19 @@ """ +# False == 0 is True def move_zeros(array): result = [] zeros = 0 for i in array: - if i == 0: # not using `not i` to avoid `False`, `[]`, etc. - zeros += 1 - else: - result.append(i) + if i == 0 and type(i) != bool: # not using `not i` to avoid `False`, `[]`, etc. + zeros += 1 + else: + result.append(i) result.extend([0] * zeros) return result + + +print(move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"])) \ No newline at end of file diff --git a/algorithms/bit/binary_gap.py b/algorithms/bit/binary_gap.py index 75a1233b5..eed32208e 100644 --- a/algorithms/bit/binary_gap.py +++ b/algorithms/bit/binary_gap.py @@ -13,6 +13,14 @@ The second consecutive pair of 1's have distance 1. The answer is the largest of these two distances, which is 2 """ + + +# 原方法为 binary_gap,但通过实验发现算法有误,不论是什么数,输出值最多为2。 +# 改进方法为binary_gap_improved。 +# The original method is binary_gap, +# but the experimental results show that the algorithm seems to be wrong, +# regardless of the number, the output value is up to 2. +# The improved method is binary_gap_improved. def binary_gap(N): last = None ans = 0 @@ -25,3 +33,25 @@ def binary_gap(N): index = index + 1 N = N >> 1 return ans + + +def binary_gap_improved(N): + last = None + ans = 0 + index = 0 + while N != 0: + tes = N & 1 + if tes: + if last is not None: + ans = max(ans, index - last + 1) + else: + last = index + else: + last = index + 1 + index = index + 1 + N = N >> 1 + return ans + + +print(binary_gap(111)) +print(binary_gap_improved(111)) \ No newline at end of file From 9cebd7a2d8a6e99c8bf5ec1595ef17d4bae97667 Mon Sep 17 00:00:00 2001 From: deli365 <55625386+deli365@users.noreply.github.com> Date: Mon, 23 Sep 2019 06:25:25 +0300 Subject: [PATCH 161/302] Added RLE algorithm (#524) * Init rle_compression file * Added encoding rle method * Added decoding rle method * Fixed typo and a bug where count would reset * RLE encode/decode unit tests * Added rle compression in README --- README.md | 1 + algorithms/compression/rle_compression.py | 58 +++++++++++++++++++++++ tests/test_compression.py | 11 +++++ 3 files changed, 70 insertions(+) create mode 100644 algorithms/compression/rle_compression.py diff --git a/README.md b/README.md index d2578e3cf..c2c62f2e8 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ If you want to uninstall algorithms, it is as simple as: - [math_parser](algorithms/calculator/math_parser.py) - [compression](algorithms/compression) - [huffman_coding](algorithms/compression/huffman_coding.py) + - [rle_compression](algorithms/compression/rle_compression.py) - [dfs](algorithms/dfs) - [all_factors](algorithms/dfs/all_factors.py) - [count_islands](algorithms/dfs/count_islands.py) diff --git a/algorithms/compression/rle_compression.py b/algorithms/compression/rle_compression.py new file mode 100644 index 000000000..b6c6df44d --- /dev/null +++ b/algorithms/compression/rle_compression.py @@ -0,0 +1,58 @@ +""" +Run-length encoding (RLE) is a simple compression algorithm +that gets a stream of data as the input and returns a +sequence of counts of consecutive data values in a row. +When decompressed the data will be fully recovered as RLE +is a lossless data compression. +""" + +def encode_rle(input): + """ + Gets a stream of data and compresses it + under a Run-Length Encoding. + :param input: The data to be encoded. + :return: The encoded string. + """ + if not input: return '' + + encoded_str = '' + prev_ch = '' + count = 1 + + for ch in input: + + # Check If the subsequent character does not match + if ch != prev_ch: + # Add the count and character + if prev_ch: + encoded_str += str(count) + prev_ch + # Reset the count and set the character + count = 1 + prev_ch = ch + else: + # Otherwise increment the counter + count += 1 + else: + return encoded_str + (str(count) + prev_ch) + + +def decode_rle(input): + """ + Gets a stream of data and decompresses it + under a Run-Length Decoding. + :param input: The data to be decoded. + :return: The decoded string. + """ + decode_str = '' + count = '' + + for ch in input: + # If not numerical + if not ch.isdigit(): + # Expand it for the decoding + decode_str += ch * int(count) + count = '' + else: + # Add it in the counter + count += ch + return decode_str diff --git a/tests/test_compression.py b/tests/test_compression.py index 611886be6..144d94466 100644 --- a/tests/test_compression.py +++ b/tests/test_compression.py @@ -1,4 +1,5 @@ from algorithms.compression.huffman_coding import HuffmanCoding +from algorithms.compression.rle_compression import (decode_rle, encode_rle) import unittest @@ -33,6 +34,16 @@ def tearDown(self): os.remove(self.file_out_bin_name) os.remove(self.file_out_name) +class TestRLECompression(unittest.TestCase): + + def test_encode_rle(self): + self.assertEqual('12W1B12W3B24W1B14W', + encode_rle('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW')) + + def test_decode_rle(self): + self.assertEqual('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW', + decode_rle('12W1B12W3B24W1B14W')) + if __name__ == "__main__": unittest.main() From 217f09238c903a6fdc18e9d793d73953a68fdecf Mon Sep 17 00:00:00 2001 From: Hojun Yoon <48780831+hojun-y@users.noreply.github.com> Date: Tue, 1 Oct 2019 01:42:38 +0900 Subject: [PATCH 162/302] Add cosine similarity calculation. (#527) * Add cosine distance calculation * Add cosine similarity to unit test and README * Fix some typo * Add docstring for cosine_similarity.py --- README.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/cosine_similarity.py | 42 +++++++++++++++++++++++++++ tests/test_maths.py | 17 +++++++++++ 4 files changed, 61 insertions(+) create mode 100644 algorithms/maths/cosine_similarity.py diff --git a/README.md b/README.md index c2c62f2e8..f30d4520e 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,7 @@ If you want to uninstall algorithms, it is as simple as: - [maths](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) + - [cosine_similarity](algorithms/maths/cosine_similarity.py) - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - [euler_totient](algorithms/maths/euler_totient.py) - [extended_gcd](algorithms/maths/extended_gcd.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 7a3fb7b00..7028a0a2c 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -14,3 +14,4 @@ from .rabin_miller import * from .rsa import * from .combination import * +from .cosine_similarity import * diff --git a/algorithms/maths/cosine_similarity.py b/algorithms/maths/cosine_similarity.py new file mode 100644 index 000000000..831e3449f --- /dev/null +++ b/algorithms/maths/cosine_similarity.py @@ -0,0 +1,42 @@ +""" +Calculate cosine similarity between given two 1d list. +Two list must have the same length. + +Example: +cosine_similarity([1, 1, 1], [1, 2, -1]) # output : 0.47140452079103173 +""" +import math + + +def _l2_distance(vec): + """ + Calculate l2 distance from two given vectors. + """ + norm = 0. + for e in vec: + norm += e * e + norm = math.sqrt(norm) + return norm + + +def cosine_similarity(a, b): + """ + Calculate cosine similarity between given two vectors + :type a: list + :type b: list + """ + if len(a) != len(b): + raise ValueError("The two vectors must be the same length. Got shape " + str(len(a)) + " and " + str(len(b))) + + norm_a = _l2_distance(a) + norm_b = _l2_distance(b) + + similarity = 0. + + # Calculate the dot product of two vectors + for ae, be in zip(a, b): + similarity += ae * be + + similarity /= (norm_a * norm_b) + + return similarity diff --git a/tests/test_maths.py b/tests/test_maths.py index dd1d0e137..850cd5d0b 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -16,6 +16,7 @@ encrypt, decrypt, combination, combination_memo, hailstone, + cosine_similarity, ) import unittest @@ -301,5 +302,21 @@ def test_hailstone(self): self.assertEqual([10, 5, 16, 8, 4, 2, 1], hailstone.hailstone(10)) +class TestCosineSimilarity(unittest.TestCase): + """[summary] + Test for the file cosine_similarity.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_cosine_similarity(self): + vec_a = [1, 1, 1] + vec_b = [-1, -1, -1] + vec_c = [1, 2, -1] + self.assertAlmostEqual(cosine_similarity(vec_a, vec_a), 1) + self.assertAlmostEqual(cosine_similarity(vec_a, vec_b), -1) + self.assertAlmostEqual(cosine_similarity(vec_a, vec_c), 0.4714045208) + + if __name__ == "__main__": unittest.main() From ca21399efac9a8b755e29b5ecbf97acac4b0885b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Me=C5=BEnar?= <32440443+smeznar@users.noreply.github.com> Date: Sun, 13 Oct 2019 12:00:20 +0200 Subject: [PATCH 163/302] Add cholesky matrix decomposition (#552) * Added algorithem for Cholesky matrix decomposition along with some of its tests. * Added time complexity. --- README.md | 1 + .../matrix/cholesky_matrix_decomposition.py | 48 +++++++++++++++++++ tests/test_matrix.py | 34 +++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 algorithms/matrix/cholesky_matrix_decomposition.py diff --git a/README.md b/README.md index f30d4520e..4b67fe51a 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,7 @@ If you want to uninstall algorithms, it is as simple as: - [sparse_mul](algorithms/matrix/sparse_mul.py) - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py) + - [cholesky_matrix_decomposition](algorithms/matrix/cholesky_matrix_decomposition.py) - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) diff --git a/algorithms/matrix/cholesky_matrix_decomposition.py b/algorithms/matrix/cholesky_matrix_decomposition.py new file mode 100644 index 000000000..4b5e24e83 --- /dev/null +++ b/algorithms/matrix/cholesky_matrix_decomposition.py @@ -0,0 +1,48 @@ +""" +Cholesky matrix decomposition is used to find the decomposition of a Hermitian positive-definite matrix A +into matrix V, so that V * V* = A, where V* denotes the conjugate transpose of L. +The dimensions of the matrix A must match. + +This method is mainly used for numeric solution of linear equations Ax = b. + +example: +Input matrix A: +[[ 4, 12, -16], + [ 12, 37, -43], + [-16, -43, 98]] + +Result: +[[2.0, 0.0, 0.0], +[6.0, 1.0, 0.0], +[-8.0, 5.0, 3.0]] + +Time complexity of this algorithm is O(n^3), specifically about (n^3)/3 + +""" +import math + + +def cholesky_decomposition(A): + """ + :param A: Hermitian positive-definite matrix of type List[List[float]] + :return: matrix of type List[List[float]] if A can be decomposed, otherwise None + """ + n = len(A) + for ai in A: + if len(ai) != n: + return None + V = [[0.0] * n for _ in range(n)] + for j in range(n): + sum_diagonal_element = 0 + for k in range(j): + sum_diagonal_element = sum_diagonal_element + math.pow(V[j][k], 2) + sum_diagonal_element = A[j][j] - sum_diagonal_element + if sum_diagonal_element <= 0: + return None + V[j][j] = math.pow(sum_diagonal_element, 0.5) + for i in range(j+1, n): + sum_other_element = 0 + for k in range(j): + sum_other_element += V[i][k]*V[j][k] + V[i][j] = (A[i][j] - sum_other_element)/V[j][j] + return V diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 4d7e129a6..3522d7dc7 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -2,6 +2,7 @@ bomb_enemy, copy_transform, crout_matrix_decomposition, + cholesky_matrix_decomposition, multiply, rotate_image, sparse_dot_vector, @@ -93,6 +94,39 @@ def test_crout_matrix_decomposition(self): [[2, 1, 3, 1], [4, 1, 4, 1], [6, 1, 7, 1], [8, 1, 9, 1]])) +class TestCholeskyMatrixDecomposition(unittest.TestCase): + """[summary] + Test for the file cholesky_matrix_decomposition.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_cholesky_matrix_decomposition(self): + self.assertEqual([[2.0, 0.0, 0.0], + [6.0, 1.0, 0.0], + [-8.0, 5.0, 3.0]], + cholesky_matrix_decomposition.cholesky_decomposition( + [[4, 12, -16], [12, 37, -43], [-16, -43, 98]])) + + self.assertEqual( None, + cholesky_matrix_decomposition.cholesky_decomposition( + [[4, 12, -8], [12, 4, -43], [-16, -1, 32]])) + + self.assertEqual(None, + cholesky_matrix_decomposition.cholesky_decomposition( + [[4, 12, -16], [12, 37, -43], [-16, -43, 98], [1, 2, 3]])) + + # example taken from https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/04LinearAlgebra/cholesky/ + self.assertEqual([[2.23606797749979, 0.0, 0.0, 0.0], + [0.5366563145999494, 2.389979079406345, 0.0, 0.0], + [0.13416407864998736, -0.19749126846635062, 2.818332343581848, 0.0], + [-0.2683281572999747, 0.43682390737048743, 0.64657701271919, 3.052723872310221]], + cholesky_matrix_decomposition.cholesky_decomposition( + [[5, 1.2, 0.3, -0.6], [1.2, 6, -0.4, 0.9], + [0.3, -0.4, 8, 1.7], [-0.6, 0.9, 1.7, 10]])) + + class TestMultiply(unittest.TestCase): """[summary] Test for the file multiply.py From b09ca797eb67c09c315746024b8155c9f591c013 Mon Sep 17 00:00:00 2001 From: Nikhil Hassija Date: Thu, 17 Oct 2019 05:26:10 +0530 Subject: [PATCH 164/302] Reformat maze_search (#555) --- algorithms/bfs/maze_search.py | 65 ++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/algorithms/bfs/maze_search.py b/algorithms/bfs/maze_search.py index 436b3ef59..f7410d46e 100644 --- a/algorithms/bfs/maze_search.py +++ b/algorithms/bfs/maze_search.py @@ -1,6 +1,8 @@ +from collections import deque + ''' -BFS time complexity : O(|E|) -BFS space complexity : O(|V|) +BFS time complexity : O(|E| + |V|) +BFS space complexity : O(|E| + |V|) do BFS from (0,0) of the grid and get the minimum number of steps needed to get to the lower right column @@ -24,25 +26,42 @@ the answer is: -1 ''' -def maze_search(grid): - dx = [0,0,-1,1] - dy = [-1,1,0,0] - n = len(grid) - m = len(grid[0]) - q = [(0,0,0)] - visit = [[0]*m for _ in range(n)] - if grid[0][0] == 0: +def maze_search(maze): + BLOCKED, ALLOWED = 0, 1 + UNVISITED, VISITED = 0, 1 + + initial_x, initial_y = 0, 0 + + if maze[initial_x][initial_y] == BLOCKED: return -1 - visit[0][0] = 1 - while q: - i, j, step = q.pop(0) - if i == n-1 and j == m-1: - return step - for k in range(4): - x = i + dx[k] - y = j + dy[k] - if x>=0 and x=0 and y Date: Thu, 17 Oct 2019 05:26:41 +0530 Subject: [PATCH 165/302] Remove debug print (#554) --- algorithms/graph/find_path.py | 1 - 1 file changed, 1 deletion(-) diff --git a/algorithms/graph/find_path.py b/algorithms/graph/find_path.py index d1716c04f..a18800555 100644 --- a/algorithms/graph/find_path.py +++ b/algorithms/graph/find_path.py @@ -21,7 +21,6 @@ def find_path(graph, start, end, path=[]): # find all path def find_all_path(graph, start, end, path=[]): path = path + [start] - print(path) if (start == end): return [path] if not start in graph: From 816bec01d51a93567db6838f5afa57913ecc538c Mon Sep 17 00:00:00 2001 From: Nikhil Hassija Date: Thu, 17 Oct 2019 05:27:05 +0530 Subject: [PATCH 166/302] Fix collections.iterable warning (#553) --- algorithms/arrays/flatten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/arrays/flatten.py b/algorithms/arrays/flatten.py index 4133c3458..f19156a09 100644 --- a/algorithms/arrays/flatten.py +++ b/algorithms/arrays/flatten.py @@ -3,7 +3,7 @@ Given an array that may contain nested arrays, produce a single resultant array. """ -from collections import Iterable +from collections.abc import Iterable # return list From 1aef871e678b028e45dccedaf4c59ad26a71f961 Mon Sep 17 00:00:00 2001 From: Pierrick <43653255+laurent-pck@users.noreply.github.com> Date: Thu, 17 Oct 2019 01:58:23 +0200 Subject: [PATCH 167/302] Black in travis ci (#551) * Add black in before_script of travis ci. * Black reformatting of the repo. * Remove python 3.5 from .travis.yml to support black * Revert "Black reformatting of the repo." This reverts commit ea0b37040692ea66fec8d1869463fa0136aceac6. * Add black or true not to make every ci fail from this PR. --- .travis.yml | 4 ++-- test_requirements.txt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37013bdae..94607d486 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,6 @@ cache: - $HOME/.cache/pip matrix: include: - - python: 3.5 - env: TOX_ENV=py35 - python: 3.6 env: TOX_ENV=py36 - python: 3.7 @@ -15,6 +13,8 @@ matrix: install: - pip install -r test_requirements.txt before_script: + # run black to check if some files would need reformatting + - black --check . || true # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide diff --git a/test_requirements.txt b/test_requirements.txt index 7a3e47c8a..f0afad0e9 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -4,3 +4,4 @@ coverage nose pytest tox +black From ebf96fab3670b42ed373c221224a8d4b17148ff3 Mon Sep 17 00:00:00 2001 From: SAYAN SANYAL <37104041+s-sanyal@users.noreply.github.com> Date: Thu, 17 Oct 2019 05:30:27 +0530 Subject: [PATCH 168/302] Added Longest Common Subsequence Algorithm under DP section (#540) --- algorithms/dp/longest_common_subsequence.py | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 algorithms/dp/longest_common_subsequence.py diff --git a/algorithms/dp/longest_common_subsequence.py b/algorithms/dp/longest_common_subsequence.py new file mode 100644 index 000000000..cdbba95b1 --- /dev/null +++ b/algorithms/dp/longest_common_subsequence.py @@ -0,0 +1,48 @@ +""" +A subsequence is a sequence that can be derived from another +sequence by deleting some or no elements without changing the +order of the remaining elements. + +For example, 'abd' is a subsequence of 'abcd' whereas 'adc' is not + +Given 2 strings containing lowercase english alphabets, find the length +of the Longest Common Subsequence (L.C.S.). + +Example: + Input: 'abcdgh' + 'aedfhr' + Output: 3 + + Explanation: The longest subsequence common to both the string is "adh" + +Time Complexity : O(M*N) +Space Complexity : O(M*N), where M and N are the lengths of the 1st and 2nd string +respectively. + +""" + + +def longest_common_subsequence(s1, s2): + """ + :param s1: string + :param s2: string + :return: int + """ + m = len(s1) + n = len(s2) + + dp = [[0] * (n + 1) for i in range(m + 1)] + """ + dp[i][j] : contains length of LCS of s1[0..i-1] and s2[0..j-1] + """ + + for i in range(m + 1): + for j in range(n + 1): + if i == 0 or j == 0: + dp[i][j] = 0 + elif s1[i - 1] == s2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + 1 + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + + return dp[m][n] From b6dbcfbf8b12883a257df1e609d28042f8ca00b7 Mon Sep 17 00:00:00 2001 From: Nikolaos Karampinas Date: Fri, 18 Oct 2019 02:13:06 +0300 Subject: [PATCH 169/302] Added elias gamma and delta data compression codings (#564) * Added elias gamma and delta data compression algorithms * Added more info about the codings. --- README.md | 1 + algorithms/compression/elias.py | 49 +++++++++++++++++++++++++++++++++ tests/test_compression.py | 20 ++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 algorithms/compression/elias.py diff --git a/README.md b/README.md index 4b67fe51a..be4c3e591 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ If you want to uninstall algorithms, it is as simple as: - [compression](algorithms/compression) - [huffman_coding](algorithms/compression/huffman_coding.py) - [rle_compression](algorithms/compression/rle_compression.py) + - [elias](algorithms/compression/elias.py) - [dfs](algorithms/dfs) - [all_factors](algorithms/dfs/all_factors.py) - [count_islands](algorithms/dfs/count_islands.py) diff --git a/algorithms/compression/elias.py b/algorithms/compression/elias.py new file mode 100644 index 000000000..bdeb7fd39 --- /dev/null +++ b/algorithms/compression/elias.py @@ -0,0 +1,49 @@ +""" +Elias γ code or Elias gamma code is a universal code encoding positive integers. +It is used most commonly when coding integers whose upper-bound cannot be determined beforehand. +Elias δ code or Elias delta code is a universal code encoding the positive integers, +that includes Elias γ code when calculating. +Both were developed by Peter Elias. + +""" +from math import log,ceil + +log2 = lambda x: log(x,2) + +# Calculates the binary number +def binary(x,l=1): + fmt = '{0:0%db}' % l + return fmt.format(x) + +# Calculates the unary number +def unary(x): + return (x-1)*'1'+'0' + +def elias_generic(lencoding, x): + """ + The compressed data is calculated in two parts. + The first part is the unary number of 1 + ⌊log2(x)⌋. + The second part is the binary number of x - 2^(⌊log2(x)⌋). + For the final result we add these two parts. + """ + if x == 0: return '0' + + first_part = 1 + int(log2(x)) + + a = x - 2**(int(log2(x))) + + k = int(log2(x)) + + return lencoding(first_part) + binary(a,k) + +def elias_gamma(x): + """ + For the first part we put the unary number of x. + """ + return elias_generic(unary, x) + +def elias_delta(x): + """ + For the first part we put the elias_g of the number. + """ + return elias_generic(elias_gamma,x) diff --git a/tests/test_compression.py b/tests/test_compression.py index 144d94466..cd412839d 100644 --- a/tests/test_compression.py +++ b/tests/test_compression.py @@ -1,5 +1,6 @@ from algorithms.compression.huffman_coding import HuffmanCoding from algorithms.compression.rle_compression import (decode_rle, encode_rle) +from algorithms.compression.elias import (elias_gamma, elias_delta) import unittest @@ -44,6 +45,25 @@ def test_decode_rle(self): self.assertEqual('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW', decode_rle('12W1B12W3B24W1B14W')) +class TestEliasCoding(unittest.TestCase): + + def test_elias_gamma(self): + correct_result = ['0', '00', '100', '101', '11000', '11001', '11010', '11011', '1110000', '1110001', '1110010'] + + result = [] + for i in range(11): + result.append(elias_gamma(i)) + + self.assertEqual(correct_result, result) + + def test_elias_delta(self): + correct_result = ['0', '000', '1000', '1001', '10100', '10101', '10110', '10111', '11000000', '11000001', '11000010'] + + result = [] + for i in range(11): + result.append(elias_delta(i)) + + self.assertEqual(correct_result, result) if __name__ == "__main__": unittest.main() From 0e427ddbebe0625e82ebc00fb6711cd2ff80d554 Mon Sep 17 00:00:00 2001 From: Nikolaos Karampinas Date: Fri, 18 Oct 2019 02:14:40 +0300 Subject: [PATCH 170/302] Added dijkstra test and missing link from documentation (#563) --- README.md | 1 + algorithms/graph/dijkstra.py | 2 +- tests/test_graph.py | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index be4c3e591..1e0029797 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ If you want to uninstall algorithms, it is as simple as: - [find_all_cliques](algorithms/graph/find_all_cliques.py) - [find_path](algorithms/graph/find_path.py) - [graph](algorithms/graph/graph.py) + - [dijkstra](algorithms/graph/dijkstra.py) - [markov_chain](algorithms/graph/markov_chain.py) - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - [satisfiability](algorithms/graph/satisfiability.py) diff --git a/algorithms/graph/dijkstra.py b/algorithms/graph/dijkstra.py index fe5772ec5..2cf043072 100644 --- a/algorithms/graph/dijkstra.py +++ b/algorithms/graph/dijkstra.py @@ -1,6 +1,6 @@ #Dijkstra's single source shortest path algorithm -class Graph(): +class Dijkstra(): def __init__(self, vertices): self.vertices = vertices diff --git a/tests/test_graph.py b/tests/test_graph.py index d402b86fa..893ea77b3 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,5 +1,6 @@ from algorithms.graph import Tarjan from algorithms.graph import check_bipartite +from algorithms.graph.dijkstra import Dijkstra import unittest @@ -57,3 +58,20 @@ def test_check_bipartite(self): adj_list_3 = [[0, 1, 0, 0], [1, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 0]] self.assertEqual(False, check_bipartite(adj_list_3)) + +class TestDijkstra(unittest.TestCase): + + def test_dijkstra(self): + g = Dijkstra(9) + g.graph = [[0, 4, 0, 0, 0, 0, 0, 8, 0], + [4, 0, 8, 0, 0, 0, 0, 11, 0], + [0, 8, 0, 7, 0, 4, 0, 0, 2], + [0, 0, 7, 0, 9, 14, 0, 0, 0], + [0, 0, 0, 9, 0, 10, 0, 0, 0], + [0, 0, 4, 14, 10, 0, 2, 0, 0], + [0, 0, 0, 0, 0, 2, 0, 1, 6], + [8, 11, 0, 0, 0, 0, 1, 0, 7], + [0, 0, 2, 0, 0, 0, 6, 7, 0] + ]; + + self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]); \ No newline at end of file From 181fd08fa735181d46c4b85d47a9aefdbaf4b157 Mon Sep 17 00:00:00 2001 From: Nikhil Hassija Date: Fri, 18 Oct 2019 04:45:05 +0530 Subject: [PATCH 171/302] Reformat arrays/limit.py (#562) --- algorithms/arrays/limit.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py index 33468a06b..c6100da1c 100644 --- a/algorithms/arrays/limit.py +++ b/algorithms/arrays/limit.py @@ -14,10 +14,7 @@ # tl:dr -- array slicing by value def limit(arr, min_lim=None, max_lim=None): - if min_lim is None and max_lim is not None: - return [x for x in arr if x <= max_lim] - if max_lim is None and min_lim is not None: - return [x for x in arr if x >= min_lim] - if max_lim is not None and min_lim is not None: - return [x for x in arr if min_lim <= x <= max_lim] - return arr + min_check = lambda val: True if min_lim is None else (min_lim <= val) + max_check = lambda val: True if max_lim is None else (val <= max_lim) + + return [val for val in arr if min_check(val) and max_check(val)] From 618f783f39fec6c3c93a77ad605e20d1d22d3291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BF=8A=E4=B9=89?= <32086937+Sean16SYSU@users.noreply.github.com> Date: Fri, 18 Oct 2019 07:15:58 +0800 Subject: [PATCH 172/302] Add_Integer_Divide Algorithms (#549) * add_integer_divide * add_integer_divide * add_integer_divide * add_integer_divide --- README.md | 1 + algorithms/dp/__init__.py | 1 + algorithms/dp/int_divide.py | 50 +++++++++++++++++++++++++++++++++++++ tests/test_dp.py | 22 ++++++++++------ 4 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 algorithms/dp/int_divide.py diff --git a/README.md b/README.md index 1e0029797..06446e6c4 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ If you want to uninstall algorithms, it is as simple as: - [combination_sum](algorithms/dp/combination_sum.py) - [egg_drop](algorithms/dp/egg_drop.py) - [house_robber](algorithms/dp/house_robber.py) + - [int_divide](algorithms/dp/int_divide.py) - [job_scheduling](algorithms/dp/job_scheduling.py) - [knapsack](algorithms/dp/knapsack.py) - [longest_increasing](algorithms/dp/longest_increasing.py) diff --git a/algorithms/dp/__init__.py b/algorithms/dp/__init__.py index 892540972..c96a9b334 100644 --- a/algorithms/dp/__init__.py +++ b/algorithms/dp/__init__.py @@ -18,3 +18,4 @@ from .regex_matching import * from .rod_cut import * from .word_break import * +from .int_divide import * diff --git a/algorithms/dp/int_divide.py b/algorithms/dp/int_divide.py new file mode 100644 index 000000000..86ba8cbb6 --- /dev/null +++ b/algorithms/dp/int_divide.py @@ -0,0 +1,50 @@ +""" +Given positive integer n, find an algorithm to find the number of non-negative number division, or descomposition. + +The complexity is O(n^2). + +Example 1: +Input: 4 +Output: 5 +Explaination: +4=4 +4=3+1 +4=2+2 +4=2+1+1 +4=1+1+1+1 + +Example : +Input: 7 +Output: 15 +Explaination: +7=7 +7=6+1 +7=5+2 +7=5+1+1 +7=4+3 +7=4+2+1 +7=4+1+1+1 +7=3+3+1 +7=3+2+2 +7=3+2+1+1 +7=3+1+1+1+1 +7=2+2+2+1 +7=2+2+1+1+1 +7=2+1+1+1+1+1 +7=1+1+1+1+1+1+1 + +""" + + +def int_divide(n): + arr = [[0 for i in range(n + 1)] for j in range(n + 1)] + arr[1][1] = 1 + for i in range(1, n + 1): + for j in range(1, n + 1): + if i < j: + arr[i][j] = arr[i][i] + elif i == j: + arr[i][j] = 1 + arr[i][j - 1] + else: + arr[i][j] = arr[i][j - 1] + arr[i - j][j] + return arr[n][n] diff --git a/tests/test_dp.py b/tests/test_dp.py index 08f6bd0a9..cd1dde291 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -10,7 +10,8 @@ house_robber, Job, schedule, Item, get_maximum_value, - longest_increasing_subsequence + longest_increasing_subsequence, + int_divide ) @@ -31,7 +32,7 @@ class TestClimbingStairs(unittest.TestCase): def test_climb_stairs(self): self.assertEqual(climb_stairs(2), 2) self.assertEqual(climb_stairs(10), 89) - + def test_climb_stairs_optimized(self): self.assertEqual(climb_stairs_optimized(2), 2) self.assertEqual(climb_stairs_optimized(10), 89) @@ -46,7 +47,7 @@ def test_count(self): class TestCombinationSum(unittest.TestCase): def test_combination_sum_topdown(self): self.assertEqual(combination_sum_topdown([1, 2, 3], 4), 7) - + def test_combination_sum_bottom_up(self): self.assertEqual(combination_sum_bottom_up([1, 2, 3], 4), 7) @@ -68,11 +69,11 @@ class TestFib(unittest.TestCase): def test_fib_recursive(self): self.assertEqual(fib_recursive(10), 55) self.assertEqual(fib_recursive(30), 832040) - + def test_fib_list(self): self.assertEqual(fib_list(10), 55) self.assertEqual(fib_list(30), 832040) - + def test_fib_iter(self): self.assertEqual(fib_iter(10), 55) self.assertEqual(fib_iter(30), 832040) @@ -85,7 +86,7 @@ class TestHosoyaTriangle(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ - + def test_hosoya(self): self.assertEqual([1], hosoya_testing(1)) self.assertEqual([1, @@ -108,7 +109,7 @@ def test_hosoya(self): hosoya_testing(10)) -class TestHouseRobber(unittest.TestCase): +class TestHouseRobber(unittest.TestCase): def test_house_robber(self): self.assertEqual(44, house_robber([1, 2, 16, 3, 15, 3, 12, 1])) @@ -134,5 +135,12 @@ def test_longest_increasing_subsequence(self): self.assertEqual(5, longest_increasing_subsequence(sequence)) +class TestIntDivide(unittest.TestCase): + def test_int_divide(self): + self.assertEqual(5, int_divide(4)) + self.assertEqual(42, int_divide(10)) + self.assertEqual(204226, int_divide(50)) + + if __name__ == '__main__': unittest.main() From 23e6404876cc83baa3516eba29d4ec0a6b965fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BF=8A=E4=B9=89?= <32086937+Sean16SYSU@users.noreply.github.com> Date: Sun, 20 Oct 2019 13:48:05 +0800 Subject: [PATCH 173/302] #567 issue fixed (#568) * add_integer_divide * add_integer_divide * add_integer_divide * add_integer_divide * README updated --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 06446e6c4..2e79f5d55 100644 --- a/README.md +++ b/README.md @@ -374,8 +374,7 @@ If you want to uninstall algorithms, it is as simple as: - [simplify_path](algorithms/unix/path/simplify_path.py) - [union-find](algorithms/union-find) - [count_islands](algorithms/union-find/count_islands.py) -- [machine-learning](algorithms/machine-learning) - - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py) + ## Contributors From d6ca8b030ce1a0c1116d85055d6e60454b77bddd Mon Sep 17 00:00:00 2001 From: phisch122 <42437430+phisch122@users.noreply.github.com> Date: Sun, 20 Oct 2019 08:14:33 +0200 Subject: [PATCH 174/302] Corrected function calls in regex_matching.py (#557) --- algorithms/dp/regex_matching.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/algorithms/dp/regex_matching.py b/algorithms/dp/regex_matching.py index 78b13c65c..72311d557 100644 --- a/algorithms/dp/regex_matching.py +++ b/algorithms/dp/regex_matching.py @@ -7,16 +7,16 @@ The matching should cover the entire input string (not partial). The function prototype should be: -bool isMatch(const char *s, const char *p) +bool is_match(const char *s, const char *p) Some examples: -isMatch("aa","a") → false -isMatch("aa","aa") → true -isMatch("aaa","aa") → false -isMatch("aa", "a*") → true -isMatch("aa", ".*") → true -isMatch("ab", ".*") → true -isMatch("aab", "c*a*b") → true +is_match("aa","a") → false +is_match("aa","aa") → true +is_match("aaa","aa") → false +is_match("aa", "a*") → true +is_match("aa", ".*") → true +is_match("ab", ".*") → true +is_match("aab", "c*a*b") → true """ import unittest @@ -60,37 +60,37 @@ class TestSolution(unittest.TestCase): def test_none_0(self): s = "" p = "" - self.assertTrue(Solution().isMatch(s, p)) + self.assertTrue(Solution().is_match(s, p)) def test_none_1(self): s = "" p = "a" - self.assertFalse(Solution().isMatch(s, p)) + self.assertFalse(Solution().is_match(s, p)) def test_no_symbol_equal(self): s = "abcd" p = "abcd" - self.assertTrue(Solution().isMatch(s, p)) + self.assertTrue(Solution().is_match(s, p)) def test_no_symbol_not_equal_0(self): s = "abcd" p = "efgh" - self.assertFalse(Solution().isMatch(s, p)) + self.assertFalse(Solution().is_match(s, p)) def test_no_symbol_not_equal_1(self): s = "ab" p = "abb" - self.assertFalse(Solution().isMatch(s, p)) + self.assertFalse(Solution().is_match(s, p)) def test_symbol_0(self): s = "" p = "a*" - self.assertTrue(Solution().isMatch(s, p)) + self.assertTrue(Solution().is_match(s, p)) def test_symbol_1(self): s = "a" p = "ab*" - self.assertTrue(Solution().isMatch(s, p)) + self.assertTrue(Solution().is_match(s, p)) def test_symbol_2(self): # E.g. @@ -101,7 +101,7 @@ def test_symbol_2(self): # * 0 1 1 1 s = "abb" p = "ab*" - self.assertTrue(Solution().isMatch(s, p)) + self.assertTrue(Solution().is_match(s, p)) if __name__ == "__main__": From 66d7f97f2ab37a2c23dfcc1946c62c136a5086fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20T=2E=20Guimar=C3=A3es?= Date: Tue, 22 Oct 2019 20:17:34 -0300 Subject: [PATCH 175/302] Add histogram algorithm (#572) * Add histogram algorithm * Add histogram in README.md * Add histogram tests * Fix typo in documentation --- README.md | 2 ++ algorithms/distribution/__init__.py | 0 algorithms/distribution/histogram.py | 28 ++++++++++++++++++++++++++++ tests/test_histogram.py | 17 +++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 algorithms/distribution/__init__.py create mode 100644 algorithms/distribution/histogram.py create mode 100644 tests/test_histogram.py diff --git a/README.md b/README.md index 2e79f5d55..a127f59b0 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ If you want to uninstall algorithms, it is as simple as: - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [distribution](algorithms/distribution) + - [histogram](algorithms/distribution/histogram.py) - [dp](algorithms/dp) - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - [climbing_stairs](algorithms/dp/climbing_stairs.py) diff --git a/algorithms/distribution/__init__.py b/algorithms/distribution/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/algorithms/distribution/histogram.py b/algorithms/distribution/histogram.py new file mode 100644 index 000000000..7bcdc7f47 --- /dev/null +++ b/algorithms/distribution/histogram.py @@ -0,0 +1,28 @@ +""" +Histogram function. + +Histogram is an accurate representation of the distribution of numerical data. +It is an estimate of the probability distribution of a continuous variable. +https://en.wikipedia.org/wiki/Histogram + +Example: + list_1 = [3, 3, 2, 1] + :return {1: 1, 2: 1, 3: 2} + + list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7] + :return {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1} +""" + + +def get_histogram(input_list: list) -> dict: + """ + Get histogram representation + :param input_list: list with different and unordered values + :return histogram: dict with histogram of input_list + """ + # Create dict to store histogram + histogram = {} + # For each list value, add one to the respective histogram dict position + for i in input_list: + histogram[i] = histogram.get(i, 0) + 1 + return histogram diff --git a/tests/test_histogram.py b/tests/test_histogram.py new file mode 100644 index 000000000..cd35bd216 --- /dev/null +++ b/tests/test_histogram.py @@ -0,0 +1,17 @@ +from algorithms.distribution.histogram import get_histogram + +import unittest + + +class TestListsInHistogram(unittest.TestCase): + def test_histogram(self): + list_1 = [3, 3, 2, 1] + list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7] + + self.assertEqual(get_histogram(list_1), {1: 1, 2: 1, 3: 2}) + self.assertEqual(get_histogram(list_2), + {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1}) + + +if __name__ == '__main__': + unittest.main() From 665b169fc96e78e2f9a495a24a64f753dfa09dc1 Mon Sep 17 00:00:00 2001 From: Jonathan Alberth Quispe Fuentes Date: Fri, 8 Nov 2019 21:25:09 -0500 Subject: [PATCH 176/302] Add iterative segment tree (#587) * Added an iterative version of segment tree * Added test for the iterative segment tree * Added readme index to iterative segment tree * Add an additional example and moves examples to the top --- README.md | 1 + .../segment_tree/iterative_segment_tree.py | 53 +++++++++++ tests/test_iterative_segment_tree.py | 91 +++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 algorithms/tree/segment_tree/iterative_segment_tree.py create mode 100644 tests/test_iterative_segment_tree.py diff --git a/README.md b/README.md index a127f59b0..f288ee39e 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,7 @@ If you want to uninstall algorithms, it is as simple as: - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - [segment_tree](algorithms/tree/segment_tree) - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [iterative_segment_tree](algorithms/tree/segment_tree/iterative_segment_tree.py) - [traversal](algorithms/tree/traversal) - [inorder](algorithms/tree/traversal/inorder.py) - [level_order](algorithms/tree/traversal/level_order.py) diff --git a/algorithms/tree/segment_tree/iterative_segment_tree.py b/algorithms/tree/segment_tree/iterative_segment_tree.py new file mode 100644 index 000000000..84018edc4 --- /dev/null +++ b/algorithms/tree/segment_tree/iterative_segment_tree.py @@ -0,0 +1,53 @@ +""" +SegmentTree creates a segment tree with a given array and a "commutative" function, +this non-recursive version uses less memory than the recursive version and include: +1. range queries in log(N) time +2. update an element in log(N) time +the function should be commutative and takes 2 values and returns the same type value + +Examples - +mytree = SegmentTree([2, 4, 5, 3, 4],max) +print(mytree.query(2, 4)) +mytree.update(3, 6) +print(mytree.query(0, 3)) ... + +mytree = SegmentTree([4, 5, 2, 3, 4, 43, 3], lambda a, b: a + b) +print(mytree.query(0, 6)) +mytree.update(2, -10) +print(mytree.query(0, 6)) ... + +mytree = SegmentTree([(1, 2), (4, 6), (4, 5)], lambda a, b: (a[0] + b[0], a[1] + b[1])) +print(mytree.query(0, 2)) +mytree.update(2, (-1, 2)) +print(mytree.query(0, 2)) ... +""" + + +class SegmentTree: + def __init__(self, arr, function): + self.tree = [None for _ in range(len(arr))] + arr + self.size = len(arr) + self.fn = function + self.build_tree() + + def build_tree(self): + for i in range(self.size - 1, 0, -1): + self.tree[i] = self.fn(self.tree[i * 2], self.tree[i * 2 + 1]) + + def update(self, p, v): + p += self.size + self.tree[p] = v + while p > 1: + p = p // 2 + self.tree[p] = self.fn(self.tree[p * 2], self.tree[p * 2 + 1]) + + def query(self, l, r): + l, r = l + self.size, r + self.size + res = None + while l <= r: + if l % 2 == 1: + res = self.tree[l] if res is None else self.fn(res, self.tree[l]) + if r % 2 == 0: + res = self.tree[r] if res is None else self.fn(res, self.tree[r]) + l, r = (l + 1) // 2, (r - 1) // 2 + return res diff --git a/tests/test_iterative_segment_tree.py b/tests/test_iterative_segment_tree.py new file mode 100644 index 000000000..b9a611a05 --- /dev/null +++ b/tests/test_iterative_segment_tree.py @@ -0,0 +1,91 @@ +from algorithms.tree.segment_tree.iterative_segment_tree import SegmentTree +from functools import reduce + +import unittest + + +def gcd(a, b): + if b == 0: + return a + return gcd(b, a % b) + + +class TestSegmentTree(unittest.TestCase): + """ + Test for the Iterative Segment Tree data structure + """ + + def test_segment_tree_creation(self): + arr = [2, 4, 3, 6, 8, 9, 3] + max_segment_tree = SegmentTree(arr, max) + min_segment_tree = SegmentTree(arr, min) + sum_segment_tree = SegmentTree(arr, lambda a, b: a + b) + gcd_segment_tree = SegmentTree(arr, gcd) + self.assertEqual(max_segment_tree.tree, [None, 9, 8, 9, 4, 8, 9, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(min_segment_tree.tree, [None, 2, 3, 2, 3, 6, 3, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(sum_segment_tree.tree, [None, 35, 21, 14, 7, 14, 12, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(gcd_segment_tree.tree, [None, 1, 1, 1, 1, 2, 3, 2, 4, 3, 6, 8, 9, 3]) + + def test_max_segment_tree(self): + arr = [-1, 1, 10, 2, 9, -3, 8, 4, 7, 5, 6, 0] + self.__test_all_segments(arr, max) + + def test_min_segment_tree(self): + arr = [1, 10, -2, 9, -3, 8, 4, -7, 5, 6, 11, -12] + self.__test_all_segments(arr, min) + + def test_sum_segment_tree(self): + arr = [1, 10, 2, 9, 3, 8, 4, 7, 5, 6, -11, -12] + self.__test_all_segments(arr, lambda a, b: a + b) + + def test_gcd_segment_tree(self): + arr = [1, 10, 2, 9, 3, 8, 4, 7, 5, 6, 11, 12, 14] + self.__test_all_segments(arr, gcd) + + def test_max_segment_tree_with_updates(self): + arr = [-1, 1, 10, 2, 9, -3, 8, 4, 7, 5, 6, 0] + updates = {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 11, 11: 12} + self.__test_all_segments_with_updates(arr, max, updates) + + def test_min_segment_tree_with_updates(self): + arr = [1, 10, -2, 9, -3, 8, 4, -7, 5, 6, 11, -12] + updates = {0: 7, 1: 2, 2: 6, 3: -14, 4: 5, 5: 4, 6: 7, 7: -10, 8: 9, 9: 10, 10: 12, 11: 1} + self.__test_all_segments_with_updates(arr, min, updates) + + def test_sum_segment_tree_with_updates(self): + arr = [1, 10, 2, 9, 3, 8, 4, 7, 5, 6, -11, -12] + updates = {0: 12, 1: 11, 2: 10, 3: 9, 4: 8, 5: 7, 6: 6, 7: 5, 8: 4, 9: 3, 10: 2, 11: 1} + self.__test_all_segments_with_updates(arr, lambda a, b: a + b, updates) + + def test_gcd_segment_tree_with_updates(self): + arr = [1, 10, 2, 9, 3, 8, 4, 7, 5, 6, 11, 12, 14] + updates = {0: 4, 1: 2, 2: 3, 3: 9, 4: 21, 5: 7, 6: 4, 7: 4, 8: 2, 9: 5, 10: 17, 11: 12, 12: 3} + self.__test_all_segments_with_updates(arr, gcd, updates) + + def __test_all_segments(self, arr, fnc): + """ + Test all possible segments in the tree + :param arr: array to test + :param fnc: function of the segment tree + """ + segment_tree = SegmentTree(arr, fnc) + self.__test_segments_helper(segment_tree, fnc, arr) + + def __test_all_segments_with_updates(self, arr, fnc, upd): + """ + Test all possible segments in the tree with updates + :param arr: array to test + :param fnc: function of the segment tree + :param upd: updates to test + """ + segment_tree = SegmentTree(arr, fnc) + for index, value in upd.items(): + arr[index] = value + segment_tree.update(index, value) + self.__test_segments_helper(segment_tree, fnc, arr) + + def __test_segments_helper(self, seg_tree, fnc, arr): + for i in range(0, len(arr)): + for j in range(i, len(arr)): + range_value = reduce(fnc, arr[i:j + 1]) + self.assertEqual(seg_tree.query(i, j), range_value) From 93b14ab8c8bd4da6855672f27045888e5f58d764 Mon Sep 17 00:00:00 2001 From: Mohd-3 <57235933+Mohd-3@users.noreply.github.com> Date: Mon, 11 Nov 2019 14:05:22 +0300 Subject: [PATCH 177/302] Add dp longest increasing optimized (#588) * added optimized algorithms for longest increasing subsequence * added optimized algorithms for longest increasing subsequence in O(nlogn) * added unittest for dp_longest_increasing --- algorithms/dp/longest_increasing.py | 89 ++++++++++++++++++++++++++++- tests/test_dp.py | 14 +++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/algorithms/dp/longest_increasing.py b/algorithms/dp/longest_increasing.py index 71971376b..6cae57299 100644 --- a/algorithms/dp/longest_increasing.py +++ b/algorithms/dp/longest_increasing.py @@ -7,14 +7,23 @@ Output: 4 Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. -The time complexity is O(n^2). +Time complexity: +First algorithm is O(n^2). +Second algorithm is O(nlogx) where x is the max element in the list +Third algorithm is O(nlogn) + +Space complexity: +First algorithm is O(n) +Second algorithm is O(x) where x is the max element in the list +Third algorithm is O(n) """ def longest_increasing_subsequence(sequence): """ Dynamic Programming Algorithm for counting the length of longest increasing subsequence - type sequence: List[int] + type sequence: list[int] + rtype: int """ length = len(sequence) counts = [1 for _ in range(length)] @@ -24,3 +33,79 @@ def longest_increasing_subsequence(sequence): counts[i] = max(counts[i], counts[j] + 1) print(counts) return max(counts) + +def longest_increasing_subsequence_optimized(sequence): + """ + Optimized dynamic programming algorithm for + couting the length of the longest increasing subsequence + using segment tree data structure to achieve better complexity + if max element is larger than 10^5 then use + longest_increasing_subsequence_optimied2() instead + type sequence: list[int] + rtype: int + """ + mx = max(sequence) + tree = [0] * (mx<<2) + + def update(p, l, r, i, v): + if l == r: + tree[p] = v + return + mid = (l+r)>>1 + if i <= mid: + update(p<<1, l, mid, i, v) + else: + update((p<<1)|1, mid+1, r, i, v) + tree[p] = max(tree[p<<1], tree[(p<<1)|1]) + + def get_max(p, l, r, s, e): + if l > e or r < s: + return 0 + if l >= s and r <= e: + return tree[p] + mid = (l+r)>>1 + return max(get_max(p<<1, l, mid, s, e), get_max((p<<1)|1, mid+1, r, s, e)) + ans = 0 + for x in sequence: + cur = get_max(1, 0, mx, 0, x-1)+1 + ans = max(ans, cur) + update(1, 0, mx, x, cur) + return ans + +def longest_increasing_subsequence_optimized2(sequence): + """ + Optimized dynamic programming algorithm for + counting the length of the longest increasing subsequence + using segment tree data structure to achieve better complexity + type sequence: list[int] + rtype: int + """ + n = len(sequence) + tree = [0] * (n<<2) + sorted_seq = sorted((x, -i) for i, x in enumerate(sequence)) + def update(p, l, r, i, v): + if l ==r: + tree[p] = v + return + mid = (l+r)>>1 + if i <= mid: + update(p<<1, l, mid, i, v) + else: + update((p<<1)|1, mid+1, r, i, v) + tree[p] = max(tree[p<<1], tree[(p<<1)|1]) + + def get_max(p, l, r, s, e): + if l > e or r < s: + return 0 + if l >= s and r <= e: + return tree[p] + mid = (l+r)>>1 + return max(get_max(p<<1, l, mid, s, e), get_max((p<<1)|1, mid+1, r, s, e)) + ans = 0 + for x, j in sorted_seq: + i = -j + cur = get_max(1, 0, n-1, 0, i-1)+1 + ans = max(ans, cur) + update(1, 0, n-1, i, cur) + return ans + diff --git a/tests/test_dp.py b/tests/test_dp.py index cd1dde291..f02921aba 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -11,6 +11,8 @@ Job, schedule, Item, get_maximum_value, longest_increasing_subsequence, + longest_increasing_subsequence_optimized, + longest_increasing_subsequence_optimized2, int_divide ) @@ -135,6 +137,18 @@ def test_longest_increasing_subsequence(self): self.assertEqual(5, longest_increasing_subsequence(sequence)) +class TestLongestIncreasingSubsequenceOptimized(unittest.TestCase): + def test_longest_increasing_subsequence_optimized(self): + sequence = [1, 101, 10, 2, 3, 100, 4, 6, 2] + self.assertEqual(5, longest_increasing_subsequence(sequence)) + + +class TestLongestIncreasingSubsequenceOptimized2(unittest.TestCase): + def test_longest_increasing_subsequence_optimized2(self): + sequence = [1, 101, 10, 2, 3, 100, 4, 6, 2] + self.assertEqual(5, longest_increasing_subsequence(sequence)) + + class TestIntDivide(unittest.TestCase): def test_int_divide(self): self.assertEqual(5, int_divide(4)) From a9aad224d6875e774cd0f7db7e30965ea6a3fbdc Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Mon, 11 Nov 2019 22:06:31 +1100 Subject: [PATCH 178/302] Fix simple typo: taget -> target (#591) --- algorithms/search/jump_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/search/jump_search.py b/algorithms/search/jump_search.py index 66f726a50..da8d8c32e 100644 --- a/algorithms/search/jump_search.py +++ b/algorithms/search/jump_search.py @@ -16,7 +16,7 @@ def jump_search(arr,target): block_prev = 0 block= block_size - # return -1 means that array doesn't contain taget value + # return -1 means that array doesn't contain target value # find block that contains target value if arr[n - 1] < target: From 9b1a4978ed776b5d3d8186153ad50dd812d802a5 Mon Sep 17 00:00:00 2001 From: sonho00 <38675117+sonho00@users.noreply.github.com> Date: Sat, 7 Dec 2019 01:03:10 +0900 Subject: [PATCH 179/302] Add gcd bit (#609) * [ADD] Added trailing_zero and gcd_bit. * [ADD] Added test case for trailing_zero and gcd_bit * [EDIT] Added spaces to code to easier to read. --- algorithms/maths/gcd.py | 39 +++++++++++++++++++++++++++++++++++++++ tests/test_maths.py | 10 +++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/algorithms/maths/gcd.py b/algorithms/maths/gcd.py index 1f80fc981..002f4fcd3 100644 --- a/algorithms/maths/gcd.py +++ b/algorithms/maths/gcd.py @@ -10,3 +10,42 @@ def gcd(a, b): def lcm(a, b): """Computes the lowest common multiple of integers a and b.""" return a * b / gcd(a, b) + + +""" +Given a positive integer x, computes the number of trailing zero of x. +Example +Input : 34(100010) + ~~~~~^ +Output : 1 + +Input : 40(101000) + ~~~^^^ +Output : 3 +""" + +def trailing_zero(x): + cnt = 0 + while x and not x & 1: + cnt += 1 + x >>= 1 + return cnt + +""" +Given two non-negative integer a and b, +computes the greatest common divisor of a and b using bitwise operator. +""" + +def gcd_bit(a, b): + tza = trailing_zero(a) + tzb = trailing_zero(b) + a >>= tza + b >>= tzb + while b: + if a < b: + a, b = b, a + a -= b + a >>= trailing_zero(a) + return a << min(tza, tzb) + + diff --git a/tests/test_maths.py b/tests/test_maths.py index 850cd5d0b..86b61e078 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -4,7 +4,7 @@ euler_totient, extended_gcd, factorial, factorial_recur, - gcd, lcm, + gcd, lcm, trailing_zero, gcd_bit, gen_strobogrammatic, strobogrammatic_in_range, is_strobogrammatic, is_strobogrammatic2, modular_exponential, @@ -101,6 +101,13 @@ def test_gcd(self): def test_lcm(self): self.assertEqual(24, lcm(8, 12)) + def test_trailing_zero(self): + self.assertEqual(1, trailing_zero(34)) + self.assertEqual(3, trailing_zero(40)) + + def test_gcd_bit(self): + self.assertEqual(4, gcd_bit(8, 12)) + self.assertEqual(1, gcd(13, 17)) class TestGenerateStroboGrammatic(unittest.TestCase): """[summary] @@ -320,3 +327,4 @@ def test_cosine_similarity(self): if __name__ == "__main__": unittest.main() + From 9fb8ce4422d213888394d95c61896c0e71e77547 Mon Sep 17 00:00:00 2001 From: Keon Date: Fri, 6 Dec 2019 08:04:26 -0800 Subject: [PATCH 180/302] Delete PULL_REQUEST_TEMPLATE.md --- PULL_REQUEST_TEMPLATE.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index ff98cafea..000000000 --- a/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,13 +0,0 @@ -(Put an `X` inside the `[ ]` to denote check mark `[X]`.) - - -- [ ] **If creating a new file :** - - [ ] added links to it in the README files ? - - [ ] included tests with it ? - - [ ] added description (overview of algorithm, time and space complexity, and possible edge case) in docstrings ? - -- [ ] **if done some changes :** - - [ ] wrote short description in the PR explaining what the changes do ? - - [ ] Fixes #[issue number] if related to any issue - -- [ ] **other** From 22818f7b77a168a95112ccf51aadd41405edf006 Mon Sep 17 00:00:00 2001 From: Mohd-3 <57235933+Mohd-3@users.noreply.github.com> Date: Fri, 6 Dec 2019 19:08:22 +0300 Subject: [PATCH 181/302] optimized coin_change (space complexity quadratic -> linear) (#593) --- algorithms/dp/coin_change.py | 43 ++++++++++++++---------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/algorithms/dp/coin_change.py b/algorithms/dp/coin_change.py index db1479633..e9a83fcbf 100644 --- a/algorithms/dp/coin_change.py +++ b/algorithms/dp/coin_change.py @@ -1,37 +1,28 @@ """ Problem -Given a value N, if we want to make change for N cents, and we have infinite supply of each of -S = { S1, S2, .. , Sm} valued //coins, how many ways can we make the change? +Given a value n, if we want to make change for N cents, and we have infinite supply of each of +coins = {S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn't matter. -For example, for N = 4 and S = [1, 2, 3], there are four solutions: +For example, for n = 4 and coins = [1, 2, 3], there are four solutions: [1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3]. So output should be 4. -For N = 10 and S = [2, 5, 3, 6], there are five solutions: +For n = 10 and coins = [2, 5, 3, 6], there are five solutions: [2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]. So the output should be 5. + +Time complexity: O(n * m) where n is the value and m is the number of coins +Space complexity: O(n) """ -def count(s, n): - # We need n+1 rows as the table is consturcted in bottom up - # manner using the base case 0 value case (n = 0) - m = len(s) - table = [[0 for x in range(m)] for x in range(n+1)] - - # Fill the enteries for 0 value case (n = 0) - for i in range(m): - table[0][i] = 1 - - # Fill rest of the table enteries in bottom up manner - for i in range(1, n+1): - for j in range(m): - # Count of solutions including S[j] - x = table[i - s[j]][j] if i-s[j] >= 0 else 0 - - # Count of solutions excluding S[j] - y = table[i][j-1] if j >= 1 else 0 +def count(coins, n): + # initialize dp array and set base case as 1 + dp = [1] + [0] * n - # total count - table[i][j] = x + y - - return table[n][m-1] + # fill dp in a bottom up manner + for coin in coins: + for i in range(coin, n+1): + dp[i] += dp[i-coin] + + return dp[n] + From f8cae20fd90c434c354f283fbb6ab4a0b5cdd287 Mon Sep 17 00:00:00 2001 From: Mohd-3 <57235933+Mohd-3@users.noreply.github.com> Date: Fri, 6 Dec 2019 19:08:39 +0300 Subject: [PATCH 182/302] simple optimizations for knapsack code (#592) --- algorithms/dp/knapsack.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/algorithms/dp/knapsack.py b/algorithms/dp/knapsack.py index 65f7d8941..530f9390b 100644 --- a/algorithms/dp/knapsack.py +++ b/algorithms/dp/knapsack.py @@ -12,7 +12,7 @@ """ -class Item(object): +class Item: def __init__(self, value, weight): self.value = value @@ -22,11 +22,7 @@ def __init__(self, value, weight): def get_maximum_value(items, capacity): dp = [0] * (capacity + 1) for item in items: - dp_tmp = [total_value for total_value in dp] - for current_weight in range(capacity + 1): - total_weight = current_weight + item.weight - if total_weight <= capacity: - dp_tmp[total_weight] = max(dp_tmp[total_weight], - dp[current_weight] + item.value) - dp = dp_tmp - return max(dp) + for cur_weight in reversed(range(item.weight, capacity+1)): + dp[cur_weight] = max(dp[cur_weight], item.value + dp[cur_weight - item.weight]) + return dp[capacity] + From 74566a34dd8e04e3cb9f44d247cef057151d9d7e Mon Sep 17 00:00:00 2001 From: Sinus <49814434+D-Sinus@users.noreply.github.com> Date: Mon, 9 Dec 2019 17:46:31 +0900 Subject: [PATCH 183/302] Add find primitive root (#608) * [Add] Find order algorithm and its supplemental * [Add] Find primitive root algorithm * [Edit] Add 'find_' in front of primitive root algorithm file * [Add/Fix] Supplemental & exception handling for the case n = 1 * [Fix] Exception handling for the case a == n == 1 in findOrder function * [Edit] Integrate find_order into find_primitive_root * [Edit] Include test cases * [Edit] Include information in readme files * [Fix] Delete misused square bracket * [Edit] Function naming convention / edit PULL_REQUEST_TEMPLATE for resolving collision --- README.md | 1 + algorithms/maths/__init__.py | 1 + .../maths/find_primitive_root_simple.py | 71 +++++++++++++++++++ tests/test_maths.py | 14 ++++ 4 files changed, 87 insertions(+) create mode 100644 algorithms/maths/find_primitive_root_simple.py diff --git a/README.md b/README.md index f288ee39e..eff0d16b3 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,7 @@ If you want to uninstall algorithms, it is as simple as: - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - [summing_digits](algorithms/maths/summing_digits.py) - [hailstone](algorithms/maths/hailstone.py) + - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - [bomb_enemy](algorithms/matrix/bomb_enemy.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 7028a0a2c..d83cfb01e 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -15,3 +15,4 @@ from .rsa import * from .combination import * from .cosine_similarity import * +from .find_primitive_root_simple import * diff --git a/algorithms/maths/find_primitive_root_simple.py b/algorithms/maths/find_primitive_root_simple.py new file mode 100644 index 000000000..a5b74f6a6 --- /dev/null +++ b/algorithms/maths/find_primitive_root_simple.py @@ -0,0 +1,71 @@ +import math + +""" +For positive integer n and given integer a that satisfies gcd(a, n) = 1, +the order of a modulo n is the smallest positive integer k that satisfies +pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n). +Order of certain number may or may not be exist. If so, return -1. +""" +def find_order(a, n): + if ((a == 1) & (n == 1)): + return 1 + """ Exception Handeling : + 1 is the order of of 1 """ + else: + if (math.gcd(a, n) != 1): + print ("a and n should be relative prime!") + return -1 + else: + for i in range(1, n): + if (pow(a, i) % n == 1): + return i + return -1 + +""" +Euler's totient function, also known as phi-function ϕ(n), +counts the number of integers between 1 and n inclusive, +which are coprime to n. +(Two numbers are coprime if their greatest common divisor (GCD) equals 1). +Code from /algorithms/maths/euler_totient.py, written by 'goswami-rahul' +""" +def euler_totient(n): + """Euler's totient function or Phi function. + Time Complexity: O(sqrt(n)).""" + result = n; + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + while n % i == 0: + n //= i + result -= result // i + if n > 1: + result -= result // n; + return result; + +""" +For positive integer n and given integer a that satisfies gcd(a, n) = 1, +a is the primitive root of n, if a's order k for n satisfies k = ϕ(n). +Primitive roots of certain number may or may not be exist. +If so, return empty list. +""" + +def find_primitive_root(n): + if (n == 1): + return [0] + """ Exception Handeling : + 0 is the only primitive root of 1 """ + else: + phi = euler_totient(n) + p_root_list = [] + """ It will return every primitive roots of n. """ + for i in range (1, n): + if (math.gcd(i, n) != 1): + continue + """ To have order, a and n must be + relative prime with each other. """ + else: + order = find_order(i, n) + if (order == phi): + p_root_list.append(i) + else: + continue + return p_root_list diff --git a/tests/test_maths.py b/tests/test_maths.py index 86b61e078..5476447bb 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -17,6 +17,7 @@ combination, combination_memo, hailstone, cosine_similarity, + find_primitive_root, ) import unittest @@ -324,6 +325,19 @@ def test_cosine_similarity(self): self.assertAlmostEqual(cosine_similarity(vec_a, vec_b), -1) self.assertAlmostEqual(cosine_similarity(vec_a, vec_c), 0.4714045208) +class TestFindPrimitiveRoot(unittest.TestCase): + """[summary] + Test for the file find_primitive_root_simple.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_find_primitive_root_simple(self): + self.assertListEqual([0], find_primitive_root(1)) + self.assertListEqual([2, 3], find_primitive_root(5)) + self.assertListEqual([], find_primitive_root(24)) + self.assertListEqual([2, 5, 13, 15, 17, 18, 19, 20, 22, 24, 32, 35], find_primitive_root(37)) + if __name__ == "__main__": unittest.main() From 55877e7f7c62605e73465c20f2bd12af836bedcc Mon Sep 17 00:00:00 2001 From: Sinus <49814434+D-Sinus@users.noreply.github.com> Date: Mon, 9 Dec 2019 17:50:06 +0900 Subject: [PATCH 184/302] Add find order (#605) * [Add] Find order algorithm and its supplemental * [Add] Find primitive root algorithm * [Edit] Add 'find_' in front of primitive root algorithm file * [Add/Fix] Supplemental & exception handling for the case n = 1 * [Fix] Exception handling for the case a == n == 1 in findOrder function * [Delete] Left find_order algorithm only in this branch * [Add] Link to find_order algorithm in the README.md * [Add] Test cases for find_order_simple.py * [Edit] Modify pull request template * [Edit] Exclude mistyped one space in README.md * [Fix] Problems in test * [Edit] Function name in algorithm file and test file * [Edit] Function name in unittest file * [Edit] Function name in unittest file (2) * [Edit] Add module information into __init__.py * [Edit] Replace PULL_REQUEST_TEMPLATE.md file for resolving conflicts --- README.md | 3 ++- algorithms/maths/__init__.py | 1 + algorithms/maths/find_order_simple.py | 27 +++++++++++++++++++++++++++ tests/test_maths.py | 14 ++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 algorithms/maths/find_order_simple.py diff --git a/README.md b/README.md index eff0d16b3..ae19560c2 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,8 @@ If you want to uninstall algorithms, it is as simple as: - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - [summing_digits](algorithms/maths/summing_digits.py) - [hailstone](algorithms/maths/hailstone.py) - - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) + - [find_order](algorithms/maths/find_order_simple.py) + - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - [bomb_enemy](algorithms/matrix/bomb_enemy.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index d83cfb01e..1cb5f7d75 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -15,4 +15,5 @@ from .rsa import * from .combination import * from .cosine_similarity import * +from .find_order_simple import * from .find_primitive_root_simple import * diff --git a/algorithms/maths/find_order_simple.py b/algorithms/maths/find_order_simple.py new file mode 100644 index 000000000..d4866ee8c --- /dev/null +++ b/algorithms/maths/find_order_simple.py @@ -0,0 +1,27 @@ +import math + +""" +For positive integer n and given integer a that satisfies gcd(a, n) = 1, +the order of a modulo n is the smallest positive integer k that satisfies +pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n). +Order of certain number may or may not be exist. If so, return -1. +""" +def find_order(a, n): + if ((a == 1) & (n == 1)): + return 1 + """ Exception Handeling : + 1 is the order of of 1 """ + else: + if (math.gcd(a, n) != 1): + print ("a and n should be relative prime!") + return -1 + else: + for i in range(1, n): + if (pow(a, i) % n == 1): + return i + return -1 + +""" +Time complexity only for calculating order = O(nlog(n)) +O(n) for iteration loop, O(log(n)) for built-in power function +""" diff --git a/tests/test_maths.py b/tests/test_maths.py index 5476447bb..ce34c3d93 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -17,6 +17,7 @@ combination, combination_memo, hailstone, cosine_similarity, + find_order, find_primitive_root, ) @@ -339,6 +340,19 @@ def test_find_primitive_root_simple(self): self.assertListEqual([2, 5, 13, 15, 17, 18, 19, 20, 22, 24, 32, 35], find_primitive_root(37)) +class TestFindOrder(unittest.TestCase): + """[summary] + Test for the file find_order_simple.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_find_order_simple(self): + self.assertEqual(1, find_order(1, 1)) + self.assertEqual(6, find_order(3, 7)) + self.assertEqual(-1, find_order(128, 256)) + self.assertEqual(352, find_order(3, 353)) + if __name__ == "__main__": unittest.main() From c6d4b7340d8e6ca333da697177d688fecac65884 Mon Sep 17 00:00:00 2001 From: NthreeAhn <39453590+NthreeAhn@users.noreply.github.com> Date: Mon, 9 Dec 2019 17:53:08 +0900 Subject: [PATCH 185/302] Add bellman-ford algorithm (#601) * fix the comment on line 33 (left->right) * [Add] bellman-ford algorithm * Update bellman_ford.py * Update merge_sort.py * Update README.md * Update bellman_ford.py * Update test_graph.py * Update bellman_ford.py * Update test_graph.py * Update test_graph.py * Update test_graph.py * Update __init__.py * Update test_graph.py * Update bellman_ford.py * Update test_graph.py --- README.md | 1 + algorithms/graph/__init__.py | 1 + algorithms/graph/bellman_ford.py | 44 ++++++++++++++++++++++++++++++++ tests/test_graph.py | 25 +++++++++++++++++- 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 algorithms/graph/bellman_ford.py diff --git a/README.md b/README.md index ae19560c2..d3bc6364e 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ If you want to uninstall algorithms, it is as simple as: - [satisfiability](algorithms/graph/satisfiability.py) - [tarjan](algorithms/graph/tarjan.py) - [traversal](algorithms/graph/traversal.py) + - [bellman_ford](algorithms/graph/bellman_ford.py) - [heap](algorithms/heap) - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - [skyline](algorithms/heap/skyline.py) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index f94f12c5c..646db09fc 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -1,2 +1,3 @@ from .tarjan import * from .check_bipartite import * +from .bellman_ford import * diff --git a/algorithms/graph/bellman_ford.py b/algorithms/graph/bellman_ford.py new file mode 100644 index 000000000..518f75c4b --- /dev/null +++ b/algorithms/graph/bellman_ford.py @@ -0,0 +1,44 @@ +''' +This Bellman-Ford Code is for determination whether we can get +shortest path from given graph or not for single-source shortest-paths problem. +In other words, if given graph has any negative-weight cycle that is reachable +from the source, then it will give answer False for "no solution exits". +For argument graph, it should be a dictionary type +such as +graph = { + 'a': {'b': 6, 'e': 7}, + 'b': {'c': 5, 'd': -4, 'e': 8}, + 'c': {'b': -2}, + 'd': {'a': 2, 'c': 7}, + 'e': {'b': -3} +} +''' + +def bellman_ford(graph, source): + weight = {} + pre_node = {} + + initialize_single_source(graph, source, weight, pre_node) + + for i in range(1, len(graph)): + for node in graph: + for adjacent in graph[node]: + if weight[adjacent] > weight[node] + graph[node][adjacent]: + weight[adjacent] = weight[node] + graph[node][adjacent] + pre_node[adjacent] = node + + for node in graph: + for adjacent in graph[node]: + if weight[adjacent] > weight[node] + graph[node][adjacent]: + return False + + return True + +def initialize_single_source(graph, source, weight, pre_node): + + for node in graph: + weight[node] = float('inf') + pre_node[node] = None + + weight[source] = 0 + diff --git a/tests/test_graph.py b/tests/test_graph.py index 893ea77b3..699136a18 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,6 +1,7 @@ from algorithms.graph import Tarjan from algorithms.graph import check_bipartite from algorithms.graph.dijkstra import Dijkstra +from algorithms.graph import bellman_ford import unittest @@ -74,4 +75,26 @@ def test_dijkstra(self): [0, 0, 2, 0, 0, 0, 6, 7, 0] ]; - self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]); \ No newline at end of file + self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]); + +class TestBellmanFord(unittest.TestCase): + def test_bellman_ford(self): + graph1 = { + 'a': {'b': 6, 'e': 7}, + 'b': {'c': 5, 'd': -4, 'e': 8}, + 'c': {'b': -2}, + 'd': {'a': 2, 'c': 7}, + 'e': {'b': -3} + } + + self.assertEqual(True, bellman_ford(graph1, 'a')) + + graph2 = { + 'a': {'d': 3, 'e': 4}, + 'b': {'a': 7, 'e':2}, + 'c': {'a': 12, 'd':9, 'e':11}, + 'd': {'c': 5, 'e': 11}, + 'e': {'a': 7, 'b': 5, 'd': 1} + } + + self.assertEqual(True, bellman_ford(graph2, 'a')) From b45667021cb196e4bfe95596ef231c5d8ecd45de Mon Sep 17 00:00:00 2001 From: lee changwon <39148949+lcw921@users.noreply.github.com> Date: Wed, 11 Dec 2019 13:27:23 +0900 Subject: [PATCH 186/302] [ADD] Create all_pairs_shortest_path.py (#599) * [ADD] Create all_pairs_shortest_path.py * [FIX]Update example and Fix Code * [FIX] Edit explanation. * Update README.md * Add unittest --- README.md | 1 + algorithms/graph/__init__.py | 1 + algorithms/graph/all_pairs_shortest_path.py | 28 +++++++++++++++++++++ tests/test_graph.py | 15 ++++++++++- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 algorithms/graph/all_pairs_shortest_path.py diff --git a/README.md b/README.md index d3bc6364e..8ddcb7ee8 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ If you want to uninstall algorithms, it is as simple as: - [satisfiability](algorithms/graph/satisfiability.py) - [tarjan](algorithms/graph/tarjan.py) - [traversal](algorithms/graph/traversal.py) + - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) - [bellman_ford](algorithms/graph/bellman_ford.py) - [heap](algorithms/heap) - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index 646db09fc..a155c77ea 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -1,3 +1,4 @@ from .tarjan import * from .check_bipartite import * +from .all_pairs_shortest_path import * from .bellman_ford import * diff --git a/algorithms/graph/all_pairs_shortest_path.py b/algorithms/graph/all_pairs_shortest_path.py new file mode 100644 index 000000000..46f3b7c09 --- /dev/null +++ b/algorithms/graph/all_pairs_shortest_path.py @@ -0,0 +1,28 @@ +""" +Given a n*n adjacency array. +it will give you all pairs shortest path length. +use deepcopy to preserve the original information. + +Time complexity : O(E^3) + +example + +a = [[0, 0.1, 0.101, 0.142, 0.277], [0.465, 0, 0.191, 0.192, 0.587], [0.245, 0.554, 0, 0.333, 0.931], [1.032, 0.668, 0.656, 0, 0.151], [0.867, 0.119, 0.352, 0.398, 0]] + +result + +[[0, 0.1, 0.101, 0.142, 0.277], [0.436, 0, 0.191, 0.192, 0.34299999999999997], [0.245, 0.345, 0, 0.333, 0.484], [0.706, 0.27, 0.46099999999999997, 0, 0.151], [0.5549999999999999, 0.119, 0.31, 0.311, 0]] + +""" +import copy + +def all_pairs_shortest_path(adjacency_matrix): + new_array = copy.deepcopy(adjacency_matrix) + + for k in range(len(new_array)): + for i in range(len(new_array)): + for j in range(len(new_array)): + if new_array[i][j] > new_array[i][k] + new_array[k][j]: + new_array[i][j] = new_array[i][k] + new_array[k][j] + + return new_array \ No newline at end of file diff --git a/tests/test_graph.py b/tests/test_graph.py index 699136a18..48c2bbb4e 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,6 +1,7 @@ from algorithms.graph import Tarjan from algorithms.graph import check_bipartite from algorithms.graph.dijkstra import Dijkstra +from algorithms.graph import all_pairs_shortest_path from algorithms.graph import bellman_ford import unittest @@ -75,7 +76,19 @@ def test_dijkstra(self): [0, 0, 2, 0, 0, 0, 6, 7, 0] ]; - self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]); + self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]) + +class TestAll_Pairs_Shortest_Path(unittest.TestCase): + + def test_all_pairs_shortest_path(self): + graph = [[0, 0.1, 0.101, 0.142, 0.277], + [0.465, 0, 0.191, 0.192, 0.587], + [0.245, 0.554, 0, 0.333, 0.931], + [1.032, 0.668, 0.656, 0, 0.151], + [0.867, 0.119, 0.352, 0.398, 0]] + result = all_pairs_shortest_path(graph) + + self.assertEqual(result, [[0, 0.1, 0.101, 0.142, 0.277], [0.436, 0, 0.191, 0.192, 0.34299999999999997], [0.245, 0.345, 0, 0.333, 0.484], [0.706, 0.27, 0.46099999999999997, 0, 0.151], [0.5549999999999999, 0.119, 0.31, 0.311, 0]]) class TestBellmanFord(unittest.TestCase): def test_bellman_ford(self): From bbad761657a710224ef147f95df6c83a4da04c0b Mon Sep 17 00:00:00 2001 From: Luke Polson <47739849+Luke-Polson@users.noreply.github.com> Date: Wed, 11 Dec 2019 17:28:06 +1300 Subject: [PATCH 187/302] Add recursive binomial coefficient (#598) * added recursive binomial coefficient algorithm * updated readme link * changed return to raise exception instead of returning a string when inputs are invalid, function now raises a ValueError exception --- README.md | 3 +- .../maths/recursive_binomial_coefficient.py | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 algorithms/maths/recursive_binomial_coefficient.py diff --git a/README.md b/README.md index 8ddcb7ee8..d188e0488 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,8 @@ If you want to uninstall algorithms, it is as simple as: - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - [summing_digits](algorithms/maths/summing_digits.py) - [hailstone](algorithms/maths/hailstone.py) - - [find_order](algorithms/maths/find_order_simple.py) + - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) + - [find_order](algorithms/maths/find_order_simple.py) - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) diff --git a/algorithms/maths/recursive_binomial_coefficient.py b/algorithms/maths/recursive_binomial_coefficient.py new file mode 100644 index 000000000..ae57bd62d --- /dev/null +++ b/algorithms/maths/recursive_binomial_coefficient.py @@ -0,0 +1,28 @@ +def recursive_binomial_coefficient(n,k): + """Calculates the binomial coefficient, C(n,k), with n>=k using recursion + Time complexity is O(k), so can calculate fairly quickly for large values of k. + + >>> recursive_binomial_coefficient(5,0) + 1 + + >>> recursive_binomial_coefficient(8,2) + 28 + + >>> recursive_binomial_coefficient(500,300) + 5054949849935535817667719165973249533761635252733275327088189563256013971725761702359997954491403585396607971745777019273390505201262259748208640 + + """ + + if k>n: + raise ValueError('Invalid Inputs, ensure that n >= k') + #function is only defined for n>=k + if k == 0 or n == k: + #C(n,0) = C(n,n) = 1, so this is our base case. + return 1 + if k > n/2: + #C(n,k) = C(n,n-k), so if n/2 is sufficiently small, we can reduce the problem size. + return recursive_binomial_coefficient(n,n-k) + else: + #else, we know C(n,k) = (n/k)C(n-1,k-1), so we can use this to reduce our problem size. + return int((n/k)*recursive_binomial_coefficient(n-1,k-1)) + From cd4f9c7562e79087031c6f040ceaf128f23c6a77 Mon Sep 17 00:00:00 2001 From: NthreeAhn <39453590+NthreeAhn@users.noreply.github.com> Date: Wed, 11 Dec 2019 13:32:00 +0900 Subject: [PATCH 188/302] Add dfa.py (#606) * fix the comment on line 33 (left->right) * add DFA.py * Update README.md * Update merge_sort.py * Create test_automata.py * Update test_automata.py * Update DFA.py * Update test_automata.py * Update test_automata.py * Create __init__.py * Update DFA.py * Update test_automata.py * Update test_automata.py * Update test_automata.py --- README.md | 2 ++ algorithms/automata/DFA.py | 18 +++++++++++++ algorithms/automata/__init__.py | 1 + tests/test_automata.py | 48 +++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 algorithms/automata/DFA.py create mode 100644 algorithms/automata/__init__.py create mode 100644 tests/test_automata.py diff --git a/README.md b/README.md index d188e0488..723f85a28 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ If you want to uninstall algorithms, it is as simple as: - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) - [n_sum](algorithms/arrays/n_sum.py) +- [automata](algorithms/automata) + - [DFA](algorithms/automata/DFA.py) - [backtrack](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [add_operators](algorithms/backtrack/add_operators.py) diff --git a/algorithms/automata/DFA.py b/algorithms/automata/DFA.py new file mode 100644 index 000000000..36211c7e8 --- /dev/null +++ b/algorithms/automata/DFA.py @@ -0,0 +1,18 @@ +def DFA(transitions, start, final, string): + + num = len(string) + num_final = len(final) + cur = start + + for i in range (num): + + if transitions[cur][string[i]] == None: + return False + else: + cur = transitions[cur][string[i]] + + for i in range (num_final): + if cur == final[i]: + return True + return False + diff --git a/algorithms/automata/__init__.py b/algorithms/automata/__init__.py new file mode 100644 index 000000000..1613fa6e3 --- /dev/null +++ b/algorithms/automata/__init__.py @@ -0,0 +1 @@ +from .DFA import * diff --git a/tests/test_automata.py b/tests/test_automata.py new file mode 100644 index 000000000..201c3d41b --- /dev/null +++ b/tests/test_automata.py @@ -0,0 +1,48 @@ +from algorithms.automata import DFA + + +import unittest + + +class TestDFA(unittest.TestCase): + def test_DFA(self): + + transitions = { + 'a': {'1': 'a', '0': 'b'}, + 'b': {'1': 'b', '0': 'a'} + } + + final=['a'] + start = 'a' + + self.assertEqual(False, DFA(transitions, start, final, "000111100")) + self.assertEqual(True, DFA(transitions, start, final, "111000011")) + + transitions1 = { + '0': {'0': '1', '1': '0'}, + '1': {'0': '2', '1': '0'}, + '2': {'0': '2', '1': '3'}, + '3': {'0': '3', '1': '3'} + } + + final1 = ['0', '1', '2'] + start1 = '0' + + self.assertEqual(False, DFA(transitions1, start1, final1, "0001111")) + self.assertEqual(True, DFA(transitions1, start1, final1, "01010101")) + + transitions2 = { + '0': {'a': '0', 'b': '1'}, + '1': {'a': '0', 'b': '2'}, + '2': {'a': '3', 'b': '2'}, + '3': {'a': '3', 'b': '3'} + } + + final2=['3'] + start2 = '0' + + self.assertEqual(False, DFA(transitions2, start2, final2, "aaabbb")) + self.assertEqual(True, DFA(transitions2, start2, final2, "baabba")) + +if __name__ == '__main__': + unittest.main() From 8261cbad9aaf35d8360760f22ca2541eeb31e982 Mon Sep 17 00:00:00 2001 From: lee changwon <39148949+lcw921@users.noreply.github.com> Date: Wed, 11 Dec 2019 13:41:13 +0900 Subject: [PATCH 189/302] [ADD] Create maximum_flow_bfs.py (#603) * [ADD] Create maximum_flow_bfs.py * Update README.md * Update README.md * [ADD] Create maximum_flow_dfs.py * Update README.md * Add unittest * Fix no newline end of file --- README.md | 2 + algorithms/graph/__init__.py | 2 + algorithms/graph/maximum_flow_bfs.py | 84 ++++++++++++++++++++++++++++ algorithms/graph/maximum_flow_dfs.py | 84 ++++++++++++++++++++++++++++ tests/test_graph.py | 56 ++++++++++++++++++- 5 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 algorithms/graph/maximum_flow_bfs.py create mode 100644 algorithms/graph/maximum_flow_dfs.py diff --git a/README.md b/README.md index 723f85a28..8569d3b1a 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,8 @@ If you want to uninstall algorithms, it is as simple as: - [satisfiability](algorithms/graph/satisfiability.py) - [tarjan](algorithms/graph/tarjan.py) - [traversal](algorithms/graph/traversal.py) + - [maximum_flow_bfs](algorithms/graph/maximum_flow_bfs.py) + - [maximum_flow_dfs](algorithms/graph/maximum_flow_dfs.py) - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) - [bellman_ford](algorithms/graph/bellman_ford.py) - [heap](algorithms/heap) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index a155c77ea..43cab3d0c 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -1,4 +1,6 @@ from .tarjan import * from .check_bipartite import * +from .maximum_flow_bfs import * +from .maximum_flow_dfs import * from .all_pairs_shortest_path import * from .bellman_ford import * diff --git a/algorithms/graph/maximum_flow_bfs.py b/algorithms/graph/maximum_flow_bfs.py new file mode 100644 index 000000000..4d2d032ff --- /dev/null +++ b/algorithms/graph/maximum_flow_bfs.py @@ -0,0 +1,84 @@ +""" +Given a n*n adjacency array. +it will give you a maximum flow. +This version use BFS to search path. + +Assume the first is the source and the last is the sink. + +Time complexity - O(Ef) + +example + +graph = [[0, 16, 13, 0, 0, 0], + [0, 0, 10, 12, 0, 0], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], + [0, 0, 0, 7, 0, 4], + [0, 0, 0, 0, 0, 0]] + +answer should be + +23 + +""" +import copy +import queue +import math + +def maximum_flow_bfs(adjacency_matrix): + #initial setting + new_array = copy.deepcopy(adjacency_matrix) + total = 0 + + while(1): + #setting min to max_value + min = math.inf + #save visited nodes + visited = [0]*len(new_array) + #save parent nodes + path = [0]*len(new_array) + + #initialize queue for BFS + bfs = queue.Queue() + + #initial setting + visited[0] = 1 + bfs.put(0) + + #BFS to find path + while(bfs.qsize() > 0): + #pop from queue + src = bfs.get() + for k in range(len(new_array)): + #checking capacity and visit + if(new_array[src][k] > 0 and visited[k] == 0 ): + #if not, put into queue and chage to visit and save path + visited[k] = 1 + bfs.put(k) + path[k] = src + + #if there is no path from src to sink + if(visited[len(new_array) - 1] == 0): + break + + #initial setting + tmp = len(new_array) - 1 + + #Get minimum flow + while(tmp != 0): + #find minimum flow + if(min > new_array[path[tmp]][tmp]): + min = new_array[path[tmp]][tmp] + tmp = path[tmp] + + #initial setting + tmp = len(new_array) - 1 + + #reduce capacity + while(tmp != 0): + new_array[path[tmp]][tmp] = new_array[path[tmp]][tmp] - min + tmp = path[tmp] + + total = total + min + + return total diff --git a/algorithms/graph/maximum_flow_dfs.py b/algorithms/graph/maximum_flow_dfs.py new file mode 100644 index 000000000..2d89d6b56 --- /dev/null +++ b/algorithms/graph/maximum_flow_dfs.py @@ -0,0 +1,84 @@ +""" +Given a n*n adjacency array. +it will give you a maximum flow. +This version use DFS to search path. + +Assume the first is the source and the last is the sink. + +Time complexity - O(Ef) + +example + +graph = [[0, 16, 13, 0, 0, 0], + [0, 0, 10, 12, 0, 0], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], + [0, 0, 0, 7, 0, 4], + [0, 0, 0, 0, 0, 0]] + +answer should be + +23 + +""" +import copy +import math + +def maximum_flow_dfs(adjacency_matrix): + #initial setting + new_array = copy.deepcopy(adjacency_matrix) + total = 0 + + while(1): + #setting min to max_value + min = math.inf + #save visited nodes + visited = [0]*len(new_array) + #save parent nodes + path = [0]*len(new_array) + + #initialize stack for DFS + stack = [] + + #initial setting + visited[0] = 1 + stack.append(0) + + #DFS to find path + while(len(stack) > 0): + #pop from queue + src = stack.pop() + for k in range(len(new_array)): + #checking capacity and visit + if(new_array[src][k] > 0 and visited[k] == 0 ): + #if not, put into queue and chage to visit and save path + visited[k] = 1 + stack.append(k) + path[k] = src + + #if there is no path from src to sink + if(visited[len(new_array) - 1] == 0): + break + + #initial setting + tmp = len(new_array) - 1 + + #Get minimum flow + while(tmp != 0): + #find minimum flow + if(min > new_array[path[tmp]][tmp]): + min = new_array[path[tmp]][tmp] + tmp = path[tmp] + + #initial setting + tmp = len(new_array) - 1 + + #reduce capacity + while(tmp != 0): + new_array[path[tmp]][tmp] = new_array[path[tmp]][tmp] - min + tmp = path[tmp] + + total = total + min + + return total + \ No newline at end of file diff --git a/tests/test_graph.py b/tests/test_graph.py index 48c2bbb4e..47d5afae0 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,9 +1,12 @@ from algorithms.graph import Tarjan from algorithms.graph import check_bipartite from algorithms.graph.dijkstra import Dijkstra +from algorithms.graph import maximum_flow_bfs +from algorithms.graph import maximum_flow_dfs from algorithms.graph import all_pairs_shortest_path from algorithms.graph import bellman_ford + import unittest @@ -78,6 +81,49 @@ def test_dijkstra(self): self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]) +class TestMaximum_Flow_Bfs(unittest.TestCase): + + """ + Test for the file def maximum_flow_bfs.py + Arguments: + unittest {[type]} -- [description] + """ + + def test_maximum_flow_bfs(self): + graph = [ + [0, 16, 13, 0, 0, 0], + [0, 0, 10, 12, 0, 0], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], + [0, 0, 0, 7, 0, 4], + [0, 0, 0, 0, 0, 0] + ] + maximum_flow = maximum_flow_bfs(graph) + + self.assertEqual(maximum_flow, 23) + +class TestMaximum_Flow_Dfs(unittest.TestCase): + + """ + Test for the file def maximum_flow_dfs.py + Arguments: + unittest {[type]} -- [description] + """ + + def test_maximum_flow_dfs(self): + graph = [ + [0, 16, 13, 0, 0, 0], + [0, 0, 10, 12, 0, 0], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], + [0, 0, 0, 7, 0, 4], + [0, 0, 0, 0, 0, 0] + ] + maximum_flow = maximum_flow_dfs(graph) + + self.assertEqual(maximum_flow, 23) + + class TestAll_Pairs_Shortest_Path(unittest.TestCase): def test_all_pairs_shortest_path(self): @@ -88,7 +134,14 @@ def test_all_pairs_shortest_path(self): [0.867, 0.119, 0.352, 0.398, 0]] result = all_pairs_shortest_path(graph) - self.assertEqual(result, [[0, 0.1, 0.101, 0.142, 0.277], [0.436, 0, 0.191, 0.192, 0.34299999999999997], [0.245, 0.345, 0, 0.333, 0.484], [0.706, 0.27, 0.46099999999999997, 0, 0.151], [0.5549999999999999, 0.119, 0.31, 0.311, 0]]) + self.assertEqual(result, [ + [0, 0.1, 0.101, 0.142, 0.277], + [0.436, 0, 0.191, 0.192, 0.34299999999999997], + [0.245, 0.345, 0, 0.333, 0.484], + [0.706, 0.27, 0.46099999999999997, 0, 0.151], + [0.5549999999999999, 0.119, 0.31, 0.311, 0], + ]) + class TestBellmanFord(unittest.TestCase): def test_bellman_ford(self): @@ -111,3 +164,4 @@ def test_bellman_ford(self): } self.assertEqual(True, bellman_ford(graph2, 'a')) + From 3e2cccbb0d7a3835bcaea333f7fa8763e3cc4bec Mon Sep 17 00:00:00 2001 From: Keon Date: Tue, 10 Dec 2019 20:53:07 -0800 Subject: [PATCH 190/302] use lowercase for file names (#620) * use lowercase filename * Rename DFA.py to dfa.py --- algorithms/automata/__init__.py | 2 +- algorithms/automata/{DFA.py => dfa.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename algorithms/automata/{DFA.py => dfa.py} (100%) diff --git a/algorithms/automata/__init__.py b/algorithms/automata/__init__.py index 1613fa6e3..bef182c6f 100644 --- a/algorithms/automata/__init__.py +++ b/algorithms/automata/__init__.py @@ -1 +1 @@ -from .DFA import * +from .dfa import * diff --git a/algorithms/automata/DFA.py b/algorithms/automata/dfa.py similarity index 100% rename from algorithms/automata/DFA.py rename to algorithms/automata/dfa.py From ee3c59523be073e6a8e9a420919ef75c38ffa0f9 Mon Sep 17 00:00:00 2001 From: sonho00 <38675117+sonho00@users.noreply.github.com> Date: Wed, 11 Dec 2019 14:02:22 +0900 Subject: [PATCH 191/302] Add network flow #595 (#610) * [ADD] Added Ford_Fulkerson algorithm. * [ADD] Added Edmonds_Karp algorithm. * [EDIT] Added time complexity to Ford_Fulkerson and Edmonds_Karp algorithm. * [ADD] Added test case for maximum flow algorithms. * [EDIT] Import maximum_flow. * [EDIT] Added link to README * [ADD] Added Dinic algorithm. * [ADD] Added test case for Dinic algorithm. * [EDIT] Edited test cases for maximum flow algorithms. * [EDIT] Edited variable name and added comment * [EDIT] Edited format to easier to recognize. * [EDIT] Edited variable name --- README.md | 1 + algorithms/graph/__init__.py | 1 + algorithms/graph/maximum_flow.py | 134 +++++++++++++++++++++++++++++++ tests/test_graph.py | 45 ++++++++++- 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 algorithms/graph/maximum_flow.py diff --git a/README.md b/README.md index 8569d3b1a..354eade65 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ If you want to uninstall algorithms, it is as simple as: - [satisfiability](algorithms/graph/satisfiability.py) - [tarjan](algorithms/graph/tarjan.py) - [traversal](algorithms/graph/traversal.py) + - [maximum_flow](algorithms/graph/maximum_flow.py) - [maximum_flow_bfs](algorithms/graph/maximum_flow_bfs.py) - [maximum_flow_dfs](algorithms/graph/maximum_flow_dfs.py) - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index 43cab3d0c..6675e6362 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -1,5 +1,6 @@ from .tarjan import * from .check_bipartite import * +from .maximum_flow import * from .maximum_flow_bfs import * from .maximum_flow_dfs import * from .all_pairs_shortest_path import * diff --git a/algorithms/graph/maximum_flow.py b/algorithms/graph/maximum_flow.py new file mode 100644 index 000000000..ca7824482 --- /dev/null +++ b/algorithms/graph/maximum_flow.py @@ -0,0 +1,134 @@ +""" +Given the capacity, source and sink of a graph, +computes the maximum flow from source to sink. +Input : capacity, source, sink +Output : maximum flow from source to sink +Capacity is a two-dimensional array that is v*v. +capacity[i][j] implies the capacity of the edge from i to j. +If there is no edge from i to j, capacity[i][j] should be zero. +""" + +import queue + +def dfs(capacity, flow, visit, vertices, idx, sink, current_flow = 1 << 63): + # DFS function for ford_fulkerson algorithm. + if idx == sink: + return current_flow + visit[idx] = True + for nxt in range(vertices): + if not visit[nxt] and flow[idx][nxt] < capacity[idx][nxt]: + tmp = dfs(capacity, flow, visit, vertices, nxt, sink, min(current_flow, capacity[idx][nxt]-flow[idx][nxt])) + if tmp: + flow[idx][nxt] += tmp + flow[nxt][idx] -= tmp + return tmp + return 0 + +def ford_fulkerson(capacity, source, sink): + # Computes maximum flow from source to sink using DFS. + # Time Complexity : O(Ef) + # E is the number of edges and f is the maximum flow in the graph. + vertices = len(capacity) + ret = 0 + flow = [[0]*vertices for i in range(vertices)] + while True: + visit = [False for i in range(vertices)] + tmp = dfs(capacity, flow, visit, vertices, source, sink) + if tmp: + ret += tmp + else: + break + return ret + +def edmonds_karp(capacity, source, sink): + # Computes maximum flow from source to sink using BFS. + # Time complexity : O(V*E^2) + # V is the number of vertices and E is the number of edges. + vertices = len(capacity) + ret = 0 + flow = [[0]*vertices for i in range(vertices)] + while True: + tmp = 0 + q = queue.Queue() + visit = [False for i in range(vertices)] + par = [-1 for i in range(vertices)] + visit[source] = True + q.put((source, 1 << 63)) + # Finds new flow using BFS. + while q.qsize(): + front = q.get() + idx, current_flow = front + if idx == sink: + tmp = current_flow + break + for nxt in range(vertices): + if not visit[nxt] and flow[idx][nxt] < capacity[idx][nxt]: + visit[nxt] = True + par[nxt] = idx + q.put((nxt, min(current_flow, capacity[idx][nxt]-flow[idx][nxt]))) + if par[sink] == -1: + break + ret += tmp + parent = par[sink] + idx = sink + # Update flow array following parent starting from sink. + while parent != -1: + flow[parent][idx] += tmp + flow[idx][parent] -= tmp + idx = parent + parent = par[parent] + return ret + +def dinic_bfs(capacity, flow, level, source, sink): + # BFS function for Dinic algorithm. + # Check whether sink is reachable only using edges that is not full. + + vertices = len(capacity) + q = queue.Queue() + q.put(source) + level[source] = 0 + while q.qsize(): + front = q.get() + for nxt in range(vertices): + if level[nxt] == -1 and flow[front][nxt] < capacity[front][nxt]: + level[nxt] = level[front] + 1 + q.put(nxt) + return level[sink] != -1 + +def dinic_dfs(capacity, flow, level, idx, sink, work, current_flow = 1 << 63): + # DFS function for Dinic algorithm. + # Finds new flow using edges that is not full. + if idx == sink: + return current_flow + vertices = len(capacity) + while work[idx] < vertices: + nxt = work[idx] + if level[nxt] == level[idx] + 1 and flow[idx][nxt] < capacity[idx][nxt]: + tmp = dinic_dfs(capacity, flow, level, nxt, sink, work, min(current_flow, capacity[idx][nxt] - flow[idx][nxt])) + if tmp > 0: + flow[idx][nxt] += tmp + flow[nxt][idx] -= tmp + return tmp + work[idx] += 1 + return 0 + +def dinic(capacity, source, sink): + # Computes maximum flow from source to sink using Dinic algorithm. + # Time complexity : O(V^2*E) + # V is the number of vertices and E is the number of edges. + vertices = len(capacity) + flow = [[0]*vertices for i in range(vertices)] + ret = 0 + while True: + level = [-1 for i in range(vertices)] + work = [0 for i in range(vertices)] + if not dinic_bfs(capacity, flow, level, source, sink): + break + while True: + tmp = dinic_dfs(capacity, flow, level, source, sink, work) + if tmp > 0: + ret += tmp + else: + break + return ret + diff --git a/tests/test_graph.py b/tests/test_graph.py index 47d5afae0..73ef23057 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,6 +1,9 @@ from algorithms.graph import Tarjan from algorithms.graph import check_bipartite from algorithms.graph.dijkstra import Dijkstra +from algorithms.graph import ford_fulkerson +from algorithms.graph import edmonds_karp +from algorithms.graph import dinic from algorithms.graph import maximum_flow_bfs from algorithms.graph import maximum_flow_dfs from algorithms.graph import all_pairs_shortest_path @@ -81,6 +84,47 @@ def test_dijkstra(self): self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]) +class TestMaximumFlow(unittest.TestCase): + """ + Test for the file maximum_flow.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_ford_fulkerson(self): + capacity = [ + [0, 10, 10, 0, 0, 0, 0], + [0, 0, 2, 0, 4, 8, 0], + [0, 0, 0, 0, 0, 9, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 10], + [0, 0, 0, 0, 6, 0, 10], + [0, 0, 0, 0, 0, 0, 0] + ] + self.assertEqual(19, ford_fulkerson(capacity, 0, 6)) + def test_edmonds_karp(self): + capacity = [ + [0, 10, 10, 0, 0, 0, 0], + [0, 0, 2, 0, 4, 8, 0], + [0, 0, 0, 0, 0, 9, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 10], + [0, 0, 0, 0, 6, 0, 10], + [0, 0, 0, 0, 0, 0, 0] + ] + self.assertEqual(19, edmonds_karp(capacity, 0, 6)) + def dinic(self): + capacity = [ + [0, 10, 10, 0, 0, 0, 0], + [0, 0, 2, 0, 4, 8, 0], + [0, 0, 0, 0, 0, 9, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 10], + [0, 0, 0, 0, 6, 0, 10], + [0, 0, 0, 0, 0, 0, 0] + ] + self.assertEqual(19, dinic(capacity, 0, 6)) + class TestMaximum_Flow_Bfs(unittest.TestCase): """ @@ -164,4 +208,3 @@ def test_bellman_ford(self): } self.assertEqual(True, bellman_ford(graph2, 'a')) - From c675bebdb6fa2848b005fd57b7ab926f00fce2a5 Mon Sep 17 00:00:00 2001 From: sonho00 <38675117+sonho00@users.noreply.github.com> Date: Wed, 11 Dec 2019 19:48:48 +0900 Subject: [PATCH 192/302] Add kmp (#611) * [ADD] Added KMP algorithm. * [ADD] Added test case for KMP algorithm * [EDIT] Imported KMP algorithm * [EDIT] Added KMP algorithm in README * [EDIT] Added test case for KMP algorithm * [EDIT] Edited description of algorithm with more detail * [FIX] Fixed minor bug * [EDIT] Added test case for edge cases --- README.md | 1 + algorithms/strings/__init__.py | 2 ++ algorithms/strings/knuth_morris_pratt.py | 34 ++++++++++++++++++++++++ tests/test_strings.py | 15 ++++++++++- 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 algorithms/strings/knuth_morris_pratt.py diff --git a/README.md b/README.md index 354eade65..bf686b8fa 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,7 @@ If you want to uninstall algorithms, it is as simple as: - [first_unique_char](algorithms/strings/first_unique_char.py) - [repeat_substring](algorithms/strings/repeat_substring.py) - [atbash_cipher](algorithms/strings/atbash_cipher.py) + - [knuth_morris_pratt](algorithms/strings/knuth_morris_pratt.py) - [tree](algorithms/tree) - [bst](algorithms/tree/bst) - [array_to_bst](algorithms/tree/bst/array_to_bst.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 9110a0f2c..3e6bc19d4 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -35,3 +35,5 @@ from .first_unique_char import * from .repeat_substring import * from .atbash_cipher import * +from .knuth_morris_pratt import * + diff --git a/algorithms/strings/knuth_morris_pratt.py b/algorithms/strings/knuth_morris_pratt.py new file mode 100644 index 000000000..0bdf4d550 --- /dev/null +++ b/algorithms/strings/knuth_morris_pratt.py @@ -0,0 +1,34 @@ +""" +Given two strings text and pattern, +return the list of start indexes in text that matches with the pattern +using knuth_morris_pratt algorithm. +If idx is in the list, text[idx : idx + M] matches with pattern. +Time complexity : O(N+M) +N and M is the length of text and pattern, respectively. +""" + +def knuth_morris_pratt(text, pattern): + n = len(text) + m = len(pattern) + pi = [0 for i in range(m)] + i = 0 + j = 0 + # making pi table + for i in range(1, m): + while j and pattern[i] != pattern[j]: + j = pi[j - 1] + if pattern[i] == pattern[j]: + j += 1 + pi[i] = j + # finding pattern + j = 0 + ret = [] + for i in range(n): + while j and text[i] != pattern[j]: + j = pi[j - 1] + if text[i] == pattern[j]: + j += 1 + if j == m: + ret.append(i - m + 1) + j = pi[j - 1] + return ret diff --git a/tests/test_strings.py b/tests/test_strings.py index 02abc6f05..b20de80e6 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -37,7 +37,8 @@ rotate, first_unique_char, repeat_substring, - atbash + atbash, + knuth_morris_pratt ) import unittest @@ -532,5 +533,17 @@ def test_atbash_cipher(self): self.assertEqual("AttaCK at DawN", atbash("ZggzXP zg WzdM")) self.assertEqual("ZggzXP zg WzdM", atbash("AttaCK at DawN")) +class TestKnuthMorrisPratt(unittest.TestCase): + """[summary] + Test for the file knuth_morris_pratt.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_knuth_morris_pratt(self): + self.assertEqual([0, 1, 2, 3, 4], knuth_morris_pratt("aaaaaaa", "aaa")) + self.assertEqual([0, 4], knuth_morris_pratt("abcdabc", "abc")) + self.assertEqual([], knuth_morris_pratt("aabcdaab", "aba")) + if __name__ == "__main__": unittest.main() From 595d1070d70b98db06844c88ee0b6107f0a96fe6 Mon Sep 17 00:00:00 2001 From: Hyunjin <38255974+guswh11@users.noreply.github.com> Date: Sat, 14 Dec 2019 07:17:49 +0900 Subject: [PATCH 193/302] Add bfs count islands (#612) * [Add] Create count_islands.py Add count_islands problem in bfs section. * [Edit] Add description in count_islands problem Add description in count_islands problem in bfs section. * [Edit] Add examples in count_islands problem Add two examples in count_islands problem in bfs section. * [Edit] Add counting_islands method Add counting_islands method in count_islands.py in bfs section. * [Edit] Modify count_islands problem in bfs Add needed variables. * [Edit] Implement counting_islands method Complete counting_islands method. * [Edit] Add examples Add test cases and testing code. * [Edit] Delete testing code * [Edit] Change method's name Change counting_islands to count_islands in count_islands problem. * [Edit] Add unittest Implement unittest func. of count_islands problem in bfs section. * [Edit] Edit count_islands method While func. is shortened. * [Delete] Delete unittest of count_islands problem This reverts commit 8cd0a662e137b44d01b7d734d5a545fa9d1d1cd4. * [Edit] Add unittest Implement unittest func. of count_islands problem and edit init file. --- algorithms/bfs/__init__.py | 1 + algorithms/bfs/count_islands.py | 65 +++++++++++++++++++++++++++++++++ tests/test_bfs.py | 16 +++++++- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 algorithms/bfs/count_islands.py diff --git a/algorithms/bfs/__init__.py b/algorithms/bfs/__init__.py index b3d3b0c6a..e61e7dbe3 100644 --- a/algorithms/bfs/__init__.py +++ b/algorithms/bfs/__init__.py @@ -1,3 +1,4 @@ +from .count_islands import * from .maze_search import * from .shortest_distance_from_all_buildings import * from .word_ladder import * diff --git a/algorithms/bfs/count_islands.py b/algorithms/bfs/count_islands.py new file mode 100644 index 000000000..5c9d00637 --- /dev/null +++ b/algorithms/bfs/count_islands.py @@ -0,0 +1,65 @@ +""" +This is a bfs-version of counting-islands problem in dfs section. +Given a 2d grid map of '1's (land) and '0's (water), +count the number of islands. +An island is surrounded by water and is formed by +connecting adjacent lands horizontally or vertically. +You may assume all four edges of the grid are all surrounded by water. + +Example 1: +11110 +11010 +11000 +00000 +Answer: 1 + +Example 2: +11000 +11000 +00100 +00011 +Answer: 3 + +Example 3: +111000 +110000 +100001 +001101 +001100 +Answer: 3 + +Example 4: +110011 +001100 +000001 +111100 +Answer: 5 +""" + + +def count_islands(grid): + row = len(grid) + col = len(grid[0]) + + num_islands = 0 + visited = [[0] * col for i in range(row)] + directions = [[-1, 0], [1, 0], [0, -1], [0, 1]] + queue = [] + + for i in range(row): + for j, num in enumerate(grid[i]): + if num == 1 and visited[i][j] != 1: + visited[i][j] = 1 + queue.append((i, j)) + while queue: + x, y = queue.pop(0) + for k in range(len(directions)): + nx_x = x + directions[k][0] + nx_y = y + directions[k][1] + if nx_x >= 0 and nx_y >= 0 and nx_x < row and nx_y < col: + if visited[nx_x][nx_y] != 1 and grid[nx_x][nx_y] == 1: + queue.append((nx_x, nx_y)) + visited[nx_x][nx_y] = 1 + num_islands += 1 + + return num_islands diff --git a/tests/test_bfs.py b/tests/test_bfs.py index 62c179bbc..98bcb7eb4 100644 --- a/tests/test_bfs.py +++ b/tests/test_bfs.py @@ -1,4 +1,5 @@ from algorithms.bfs import ( + count_islands, maze_search, shortest_distance_from_all_buildings, ladder_length @@ -7,8 +8,21 @@ import unittest +class TestCountIslands(unittest.TestCase): + + def test_count_islands(self): + grid_1 = [[1,1,1,1,0], [1,1,0,1,0], [1,1,0,0,0], [0,0,0,0,0]] + self.assertEqual(1, count_islands(grid_1)) + grid_2 = [[1,1,0,0,0], [1,1,0,0,0], [0,0,1,0,0], [0,0,0,1,1]] + self.assertEqual(3, count_islands(grid_2)) + grid_3 = [[1,1,1,0,0,0], [1,1,0,0,0,0], [1,0,0,0,0,1], [0,0,1,1,0,1], [0,0,1,1,0,0]] + self.assertEqual(3, count_islands(grid_3)) + grid_4 = [[1,1,0,0,1,1], [0,0,1,1,0,0], [0,0,0,0,0,1], [1,1,1,1,0,0]] + self.assertEqual(5, count_islands(grid_4)) + + class TestMazeSearch(unittest.TestCase): - + def test_maze_search(self): grid_1 = [[1,0,1,1,1,1],[1,0,1,0,1,0],[1,0,1,0,1,1],[1,1,1,0,1,1]] self.assertEqual(14, maze_search(grid_1)) From 63fa0a24f103dc0e26b55edf75d901de82e37844 Mon Sep 17 00:00:00 2001 From: Hyunjin <38255974+guswh11@users.noreply.github.com> Date: Sat, 14 Dec 2019 07:22:31 +0900 Subject: [PATCH 194/302] Add dfs maze search (#613) * [Add] Create maze_search.py Add maze_search.py in dfs section. * [Edit] Add description and examples Add description and examples in maze_search problem. * [Edit] Add methods in maze_search Add find_path and dfs methods in dfs_maze_search problem. * [Edit] Add global variable Add global variable directions in maze_search problem in dfs section. * [Edit] Add global variable Add global variable cnt in maze_search problem in dfs section. * [Edit] Add return condition Add return condition of dfs method. * [Edit] Add code in dfs method Move i and j following defined directions. * [Edit] Add code in dfs method Implement recursive call in dfs method. * [Fix] Implement dfs method Fix wrong variable names in dfs method. * [Edit] Add dfs method call and testing code Complete find_path method and add testing code. * [Edit] Delete testing code * [Edit] Delete global variable Change global variable directions to local variable. * [Edit] Delete global variable Change global variable cnt to local variable. * [Edit] Add description Add description in maze_search problem in dfs section. * [Edit] Add unittest Implement unittest func. of maze_search problem and edit init file. * [Edit] Edit unittest Change wrong test answer. --- algorithms/dfs/__init__.py | 1 + algorithms/dfs/maze_search.py | 55 +++++++++++++++++++++++++++++++++++ tests/test_dfs.py | 11 ++++++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 algorithms/dfs/maze_search.py diff --git a/algorithms/dfs/__init__.py b/algorithms/dfs/__init__.py index 03af1291e..043414c1e 100644 --- a/algorithms/dfs/__init__.py +++ b/algorithms/dfs/__init__.py @@ -3,3 +3,4 @@ from .pacific_atlantic import * from .sudoku_solver import * from .walls_and_gates import * +from .maze_search import * diff --git a/algorithms/dfs/maze_search.py b/algorithms/dfs/maze_search.py new file mode 100644 index 000000000..f644fd5a6 --- /dev/null +++ b/algorithms/dfs/maze_search.py @@ -0,0 +1,55 @@ +''' +Find shortest path from top left column to the right lowest column using DFS. +only step on the columns whose value is 1 +if there is no path, it returns -1 +(The first column(top left column) is not included in the answer.) + +Ex 1) +If maze is +[[1,0,1,1,1,1], + [1,0,1,0,1,0], + [1,0,1,0,1,1], + [1,1,1,0,1,1]], +the answer is: 14 + +Ex 2) +If maze is +[[1,0,0], + [0,1,1], + [0,1,1]], +the answer is: -1 +''' + + +def find_path(maze): + cnt = dfs(maze, 0, 0, 0, -1) + return cnt + + +def dfs(maze, i, j, depth, cnt): + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + + row = len(maze) + col = len(maze[0]) + + if i == row - 1 and j == col - 1: + if cnt == -1: + cnt = depth + else: + if cnt > depth: + cnt = depth + return cnt + + maze[i][j] = 0 + + for k in range(len(directions)): + nx_i = i + directions[k][0] + nx_j = j + directions[k][1] + + if nx_i >= 0 and nx_i < row and nx_j >= 0 and nx_j < col: + if maze[nx_i][nx_j] == 1: + cnt = dfs(maze, nx_i, nx_j, depth + 1, cnt) + + maze[i][j] = 1 + + return cnt diff --git a/tests/test_dfs.py b/tests/test_dfs.py index ed1c3f263..0f198e4a9 100644 --- a/tests/test_dfs.py +++ b/tests/test_dfs.py @@ -3,7 +3,8 @@ num_islands, pacific_atlantic, Sudoku, - walls_and_gates + walls_and_gates, + find_path ) import unittest @@ -50,6 +51,14 @@ def test_walls_and_gates(self): walls_and_gates(rooms) self.assertEqual([[3, -1, 0, 1], [2, 2, 1, -1], [1, -1, 2, -1], [0, -1, 3, 4]], rooms) +class TestMazeSearch(unittest.TestCase): + def test_maze_search(self): + maze_1 = [[1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1], [1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1]] + self.assertEqual(37, find_path(maze_1)) + maze_2 = [[1,0,1,1,1,1], [1,0,1,0,1,0], [1,0,1,0,1,1], [1,1,1,0,1,1]] + self.assertEqual(14, find_path(maze_2)) + maze_3 = [[1,0,0], [0,1,1], [0,1,1]] + self.assertEqual(-1, find_path(maze_3)) if __name__ == "__main__": unittest.main() \ No newline at end of file From 29b310d1a36ca39afe0acfe7b8189440dbf1f4f0 Mon Sep 17 00:00:00 2001 From: Sinus <49814434+D-Sinus@users.noreply.github.com> Date: Sun, 22 Dec 2019 23:54:34 +0900 Subject: [PATCH 195/302] Add diffie hellman key exchange (#615) * [Add] Find order algorithm and its supplemental * [Add] Find primitive root algorithm * [Edit] Add 'find_' in front of primitive root algorithm file * [Add/Fix] Supplemental & exception handling for the case n = 1 * [Fix] Exception handling for the case a == n == 1 in findOrder function * [Delete] Algorithms in my other branch * [Add] Diffie-Hellman Key Exchange Illustration * [Add] Description for Diffie-Hellman Key exchange * [Add] Supplemental for DH Key Exchange * [Add] Test and its operating environment * [Edit] Add link to README.md file * [Edit] For not primitive root case, code raise ValueError now * [Edit] Change test cases according to immediate before commit * [Edit] For not primitive root case, code return False now, for consistency (return Bool only) * Change test cases according to immediate before commit * [Edit] If optional parameter is given, additional explanation would arise --- README.md | 1 + algorithms/maths/__init__.py | 1 + .../maths/diffie_hellman_key_exchange.py | 190 ++++++++++++++++++ tests/test_maths.py | 16 ++ 4 files changed, 208 insertions(+) create mode 100644 algorithms/maths/diffie_hellman_key_exchange.py diff --git a/README.md b/README.md index bf686b8fa..7996cc599 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,7 @@ If you want to uninstall algorithms, it is as simple as: - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) - [find_order](algorithms/maths/find_order_simple.py) - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) + - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - [bomb_enemy](algorithms/matrix/bomb_enemy.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 1cb5f7d75..7b8a7b1ec 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -17,3 +17,4 @@ from .cosine_similarity import * from .find_order_simple import * from .find_primitive_root_simple import * +from .diffie_hellman_key_exchange import * diff --git a/algorithms/maths/diffie_hellman_key_exchange.py b/algorithms/maths/diffie_hellman_key_exchange.py new file mode 100644 index 000000000..5fed8efa1 --- /dev/null +++ b/algorithms/maths/diffie_hellman_key_exchange.py @@ -0,0 +1,190 @@ +import math +from random import randint + +""" +Code from /algorithms/maths/prime_check.py, +written by 'goswami-rahul' and 'Hai Honag Dang' +""" +def prime_check(n): + """Return True if n is a prime number + Else return False. + """ + + if n <= 1: + return False + if n == 2 or n == 3: + return True + if n % 2 == 0 or n % 3 == 0: + return False + j = 5 + while j * j <= n: + if n % j == 0 or n % (j + 2) == 0: + return False + j += 6 + return True + + +""" +For positive integer n and given integer a that satisfies gcd(a, n) = 1, +the order of a modulo n is the smallest positive integer k that satisfies +pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n). +Order of certain number may or may not be exist. If so, return -1. +""" +def find_order(a, n): + if ((a == 1) & (n == 1)): + return 1 + """ Exception Handeling : + 1 is the order of of 1 """ + else: + if (math.gcd(a, n) != 1): + print ("a and n should be relative prime!") + return -1 + else: + for i in range(1, n): + if (pow(a, i) % n == 1): + return i + return -1 + +""" +Euler's totient function, also known as phi-function ϕ(n), +counts the number of integers between 1 and n inclusive, +which are coprime to n. +(Two numbers are coprime if their greatest common divisor (GCD) equals 1). +Code from /algorithms/maths/euler_totient.py, written by 'goswami-rahul' +""" +def euler_totient(n): + """Euler's totient function or Phi function. + Time Complexity: O(sqrt(n)).""" + result = n; + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + while n % i == 0: + n //= i + result -= result // i + if n > 1: + result -= result // n; + return result; + +""" +For positive integer n and given integer a that satisfies gcd(a, n) = 1, +a is the primitive root of n, if a's order k for n satisfies k = ϕ(n). +Primitive roots of certain number may or may not be exist. +If so, return empty list. +""" + +def find_primitive_root(n): + if (n == 1): + return [0] + """ Exception Handeling : + 0 is the only primitive root of 1 """ + else: + phi = euler_totient(n) + p_root_list = [] + """ It will return every primitive roots of n. """ + for i in range (1, n): + if (math.gcd(i, n) != 1): + continue + """ To have order, a and n must be + relative prime with each other. """ + else: + order = find_order(i, n) + if (order == phi): + p_root_list.append(i) + else: + continue + return p_root_list + + +""" +Diffie-Hellman key exchange is the method that enables +two entities (in here, Alice and Bob), not knowing each other, +to share common secret key through not-encrypted communication network. +This method use the property of one-way function (discrete logarithm) +For example, given a, b and n, it is easy to calculate x +that satisfies (a^b) ≡ x (mod n). +However, it is very hard to calculate x that satisfies (a^x) ≡ b (mod n). +For using this method, large prime number p and its primitive root a must be given. +""" + +def alice_private_key(p): + """Alice determine her private key + in the range of 1 ~ p-1. + This must be kept in secret""" + return randint(1, p-1) + + +def alice_public_key(a_pr_k, a, p): + """Alice calculate her public key + with her private key. + This is open to public""" + return pow(a, a_pr_k) % p + + +def bob_private_key(p): + """Bob determine his private key + in the range of 1 ~ p-1. + This must be kept in secret""" + return randint(1, p-1) + + +def bob_public_key(b_pr_k, a, p): + """Bob calculate his public key + with his private key. + This is open to public""" + return pow(a, b_pr_k) % p + + +def alice_shared_key(b_pu_k, a_pr_k, p): + """ Alice calculate secret key shared with Bob, + with her private key and Bob's public key. + This must be kept in secret""" + return pow(b_pu_k, a_pr_k) % p + + +def bob_shared_key(a_pu_k, b_pr_k, p): + """ Bob calculate secret key shared with Alice, + with his private key and Alice's public key. + This must be kept in secret""" + return pow(a_pu_k, b_pr_k) % p + + +def diffie_hellman_key_exchange(a, p, option = None): + if (option != None): + option = 1 + """ Print explanation of process + when option parameter is given """ + if (prime_check(p) == False): + print("%d is not a prime number" % p) + return False + """p must be large prime number""" + else: + try: + p_root_list = find_primitive_root(p) + p_root_list.index(a) + except ValueError: + print("%d is not a primitive root of %d" % (a, p)) + return False + """ a must be primitive root of p """ + + a_pr_k = alice_private_key(p) + a_pu_k = alice_public_key(a_pr_k, a, p) + + + b_pr_k = bob_private_key(p) + b_pu_k = bob_public_key(b_pr_k, a, p) + + if (option == 1): + print ("Private key of Alice = %d" % a_pr_k) + print ("Public key of Alice = %d" % a_pu_k) + print ("Private key of Bob = %d" % b_pr_k) + print ("Public key of Bob = %d" % b_pu_k) + + """ In here, Alice send her public key to Bob, + and Bob also send his public key to Alice.""" + + a_sh_k = alice_shared_key(b_pu_k, a_pr_k, p) + b_sh_k = bob_shared_key(a_pu_k, b_pr_k, p) + print ("Shared key calculated by Alice = %d" % a_sh_k) + print ("Shared key calculated by Bob = %d" % b_sh_k) + + return (a_sh_k == b_sh_k) diff --git a/tests/test_maths.py b/tests/test_maths.py index ce34c3d93..c29a8664a 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -19,6 +19,7 @@ cosine_similarity, find_order, find_primitive_root, + alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange ) import unittest @@ -326,6 +327,7 @@ def test_cosine_similarity(self): self.assertAlmostEqual(cosine_similarity(vec_a, vec_b), -1) self.assertAlmostEqual(cosine_similarity(vec_a, vec_c), 0.4714045208) + class TestFindPrimitiveRoot(unittest.TestCase): """[summary] Test for the file find_primitive_root_simple.py @@ -353,6 +355,20 @@ def test_find_order_simple(self): self.assertEqual(-1, find_order(128, 256)) self.assertEqual(352, find_order(3, 353)) + +class TestDiffieHellmanKeyExchange(unittest.TestCase): + """[summary] + Test for the file diffie_hellman_key_exchange.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_find_order_simple(self): + self.assertFalse(diffie_hellman_key_exchange(3, 6)) + self.assertTrue(diffie_hellman_key_exchange(3, 353)) + self.assertFalse(diffie_hellman_key_exchange(5, 211)) + self.assertTrue(diffie_hellman_key_exchange(11, 971)) + if __name__ == "__main__": unittest.main() From 2f84f0399de525d35e38bb6da75489343a280ce3 Mon Sep 17 00:00:00 2001 From: Keon Date: Thu, 26 Dec 2019 01:31:08 -0800 Subject: [PATCH 196/302] organize files and remove calculator & iterables (#623) --- README.md | 8 +- algorithms/calculator/math_parser.py | 149 ----- ...osure_DFS.py => transitive_closure_dfs.py} | 20 +- algorithms/iterables/__init__.py | 1 - algorithms/iterables/convolved.py | 154 ----- algorithms/matrix/matrix_rotation.txt | 580 ------------------ .../count_islands.py | 0 tests/test_graph.py | 1 + tests/test_iterables.py | 161 ----- 9 files changed, 13 insertions(+), 1061 deletions(-) delete mode 100644 algorithms/calculator/math_parser.py rename algorithms/graph/{Transitive_Closure_DFS.py => transitive_closure_dfs.py} (85%) delete mode 100644 algorithms/iterables/__init__.py delete mode 100644 algorithms/iterables/convolved.py delete mode 100644 algorithms/matrix/matrix_rotation.txt rename algorithms/{union-find => unionfind}/count_islands.py (100%) delete mode 100644 tests/test_iterables.py diff --git a/README.md b/README.md index 7996cc599..53b8c691d 100644 --- a/README.md +++ b/README.md @@ -113,8 +113,6 @@ If you want to uninstall algorithms, it is as simple as: - [insert_bit](algorithms/bit/insert_bit.py) - [remove_bit](algorithms/bit/remove_bit.py) - [binary_gap](algorithms/bit/binary_gap.py) -- [calculator](algorithms/calculator) - - [math_parser](algorithms/calculator/math_parser.py) - [compression](algorithms/compression) - [huffman_coding](algorithms/compression/huffman_coding.py) - [rle_compression](algorithms/compression/rle_compression.py) @@ -172,8 +170,6 @@ If you want to uninstall algorithms, it is as simple as: - [skyline](algorithms/heap/skyline.py) - [sliding_window_max](algorithms/heap/sliding_window_max.py) - [binary_heap](algorithms/heap/binary_heap.py) -- [iterables](algorithms/iterables) - - [convolved](algorithms/iterables/convolved.py) - [k_closest_points](algorithms/heap/k_closest_points.py) - [linkedlist](algorithms/linkedlist) - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) @@ -387,8 +383,8 @@ If you want to uninstall algorithms, it is as simple as: - [full_path](algorithms/unix/path/full_path.py) - [split](algorithms/unix/path/split.py) - [simplify_path](algorithms/unix/path/simplify_path.py) -- [union-find](algorithms/union-find) - - [count_islands](algorithms/union-find/count_islands.py) +- [unionfind](algorithms/unionfind) + - [count_islands](algorithms/unionfind/count_islands.py) ## Contributors diff --git a/algorithms/calculator/math_parser.py b/algorithms/calculator/math_parser.py deleted file mode 100644 index 3cbe1cb56..000000000 --- a/algorithms/calculator/math_parser.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -Contributed by izanbf1803. - -Example: -------------------------------------------------------------------------------------------------- - Code: - | exp = "2452 * (3 * 6.5 + 1) * 6 / 235" - | print("Expression:", exp) - | print("Parsed expression:", mp.parse(exp)) - | print("Evaluation result:", mp.evaluate(exp)) - - Output: - | Expression: 2452 * (3 * 6 + 1) * 6 / 235 - | Parsed expression: ['2452', '*', '(', '3', '*', '6', '+', '1', ')', '*', '6', '/', '235'] - | Evaluation result: 1189.4808510638297 -------------------------------------------------------------------------------------------------- - -Now added '^' operator for exponents. (by @goswami-rahul) -""" - -from collections import deque -import re - -numeric_value = re.compile('\d+(\.\d+)?') - -__operators__ = "+-/*^" -__parenthesis__ = "()" -__priority__ = { - '+': 0, - '-': 0, - '*': 1, - '/': 1, - '^': 2 -} - -def is_operator(token): - """ - Check if token it's a operator - - token Char: Token - """ - return token in __operators__ - -def higher_priority(op1, op2): - """ - Check if op1 have higher priority than op2 - - op1 Char: Operation Token 1 - op2 Char: Operation Token 2 - """ - return __priority__[op1] >= __priority__[op2] - -def calc(n2, n1, operator): - """ - Calculate operation result - - n2 Number: Number 2 - n1 Number: Number 1 - operator Char: Operation to calculate - """ - if operator == '-': return n1 - n2 - elif operator == '+': return n1 + n2 - elif operator == '*': return n1 * n2 - elif operator == '/': return n1 / n2 - elif operator == '^': return n1 ** n2 - return 0 - -def apply_operation(op_stack, out_stack): - """ - Apply operation to the first 2 items of the output queue - - op_stack Deque (reference) - out_stack Deque (reference) - """ - out_stack.append(calc(out_stack.pop(), out_stack.pop(), op_stack.pop())) - -def parse(expression): - """ - Return array of parsed tokens in the expression - - expression String: Math expression to parse in infix notation - """ - result = [] - current = "" - for i in expression: - if i.isdigit() or i == '.': - current += i - else: - if len(current) > 0: - result.append(current) - current = "" - if i in __operators__ or i in __parenthesis__: - result.append(i) - else: - raise Exception("invalid syntax " + i) - - if len(current) > 0: - result.append(current) - return result - -def evaluate(expression): - """ - Calculate result of expression - - expression String: The expression - type Type (optional): Number type [int, float] - """ - op_stack = deque() # operator stack - out_stack = deque() # output stack (values) - tokens = parse(expression) # calls the function only once! - for token in tokens: - if numeric_value.match(token): - out_stack.append(float(token)) - elif token == '(': - op_stack.append(token) - elif token == ')': - while len(op_stack) > 0 and op_stack[-1] != '(': - apply_operation(op_stack, out_stack) - op_stack.pop() # Remove remaining '(' - else: # is_operator(token) - while len(op_stack) > 0 and is_operator(op_stack[-1]) and higher_priority(op_stack[-1], token): - apply_operation(op_stack, out_stack) - op_stack.append(token) - - while len(op_stack) > 0: - apply_operation(op_stack, out_stack) - - return out_stack[-1] - - -def main(): - """ - simple user-interface - """ - print("\t\tCalculator\n\n") - while True: - user_input = input("expression or exit: ") - if user_input == "exit": - break - try: - print("The result is {0}".format(evaluate(user_input))) - except Exception: - print("invalid syntax!") - user_input = input("expression or exit: ") - print("program end") - - -if __name__ == "__main__": - main() diff --git a/algorithms/graph/Transitive_Closure_DFS.py b/algorithms/graph/transitive_closure_dfs.py similarity index 85% rename from algorithms/graph/Transitive_Closure_DFS.py rename to algorithms/graph/transitive_closure_dfs.py index 8e8e74da4..655c75c89 100644 --- a/algorithms/graph/Transitive_Closure_DFS.py +++ b/algorithms/graph/transitive_closure_dfs.py @@ -40,13 +40,13 @@ def transitive_closure(self): print(self.tc) -g = Graph(4) -g.add_edge(0, 1) -g.add_edge(0, 2) -g.add_edge(1, 2) -g.add_edge(2, 0) -g.add_edge(2, 3) -g.add_edge(3, 3) - -print("Transitive closure matrix is") -g.transitive_closure() +# g = Graph(4) +# g.add_edge(0, 1) +# g.add_edge(0, 2) +# g.add_edge(1, 2) +# g.add_edge(2, 0) +# g.add_edge(2, 3) +# g.add_edge(3, 3) + +# print("Transitive closure matrix is") +# g.transitive_closure() diff --git a/algorithms/iterables/__init__.py b/algorithms/iterables/__init__.py deleted file mode 100644 index f39a0ffd5..000000000 --- a/algorithms/iterables/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .convolved import * diff --git a/algorithms/iterables/convolved.py b/algorithms/iterables/convolved.py deleted file mode 100644 index 4f8b49288..000000000 --- a/algorithms/iterables/convolved.py +++ /dev/null @@ -1,154 +0,0 @@ -"""Iterable to get every convolution window per loop iteration. - -## Example Usage - -``` -from algorithms.iterables import convolved -# This would also work: from conv import convolved - -some_list = [1, 2, 3] -for kernel_hover in convolved(some_list, kernel_size=2, stride=1, padding=2, default_value=42): - print(kernel_hover) -``` - -## Result: - -``` -[42, 42] -[42, 1] -[1, 2] -[2, 3] -[3, 42] -[42, 42] -``` - -""" - - -def convolved(iterable, kernel_size=1, stride=1, padding=0, default_value=None): - """Iterable to get every convolution window per loop iteration. - - For example: - `convolved([1, 2, 3, 4], kernel_size=2)` - will produce the following result: - `[[1, 2], [2, 3], [3, 4]]`. - `convolved([1, 2, 3], kernel_size=2, stride=1, padding=2, default_value=42)` - will produce the following result: - `[[42, 42], [42, 1], [1, 2], [2, 3], [3, 42], [42, 42]]` - - Arguments: - iterable: An object to iterate on. It should support slice indexing if `padding == 0`. - kernel_size: The number of items yielded at every iteration. - stride: The step size between each iteration. - padding: Padding must be an integer or a string with value `SAME` or `VALID`. If it is an integer, it represents - how many values we add with `default_value` on the borders. If it is a string, `SAME` means that the - convolution will add some padding according to the kernel_size, and `VALID` is the same as - specifying `padding=0`. - default_value: Default fill value for padding and values outside iteration range. - - For more information, refer to: - - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py - - https://github.com/guillaume-chevalier/python-conv-lib - - MIT License, Copyright (c) 2018 Guillaume Chevalier - """ - # Input validation and error messages - if not hasattr(iterable, '__iter__'): - raise ValueError( - "Can't iterate on object.".format( - iterable)) - if stride < 1: - raise ValueError( - "Stride must be of at least one. Got `stride={}`.".format( - stride)) - if not (padding in ['SAME', 'VALID'] or type(padding) in [int]): - raise ValueError( - "Padding must be an integer or a string with value `SAME` or `VALID`.") - if not isinstance(padding, str): - if padding < 0: - raise ValueError( - "Padding must be of at least zero. Got `padding={}`.".format( - padding)) - else: - if padding == 'SAME': - padding = kernel_size // 2 - elif padding == 'VALID': - padding = 0 - if not type(iterable) == list: - iterable = list(iterable) - - # Add padding to iterable - if padding > 0: - pad = [default_value] * padding - iterable = pad + list(iterable) + pad - - # Fill missing value to the right - remainder = (kernel_size - len(iterable)) % stride - extra_pad = [default_value] * remainder - iterable = iterable + extra_pad - - i = 0 - while True: - if i > len(iterable) - kernel_size: - break - yield iterable[i:i + kernel_size] - i += stride - -def convolved_1d(iterable, kernel_size=1, stride=1, padding=0, default_value=None): - """1D Iterable to get every convolution window per loop iteration. - - For more information, refer to: - - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py - - https://github.com/guillaume-chevalier/python-conv-lib - - MIT License, Copyright (c) 2018 Guillaume Chevalier - """ - return convolved(iterable, kernel_size, stride, padding, default_value) - - -def convolved_2d(iterable, kernel_size=1, stride=1, padding=0, default_value=None): - """2D Iterable to get every convolution window per loop iteration. - - For more information, refer to: - - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py - - https://github.com/guillaume-chevalier/python-conv-lib - - MIT License, Copyright (c) 2018 Guillaume Chevalier - """ - kernel_size = dimensionize(kernel_size, nd=2) - stride = dimensionize(stride, nd=2) - padding = dimensionize(padding, nd=2) - - for row_packet in convolved(iterable, kernel_size[0], stride[0], padding[0], default_value): - transposed_inner = [] - for col in tuple(row_packet): - transposed_inner.append(list( - convolved(col, kernel_size[1], stride[1], padding[1], default_value) - )) - - if len(transposed_inner) > 0: - for col_i in range(len(transposed_inner[0])): - yield tuple(row_j[col_i] for row_j in transposed_inner) - - -def dimensionize(maybe_a_list, nd=2): - """Convert integers to a list of integers to fit the number of dimensions if - the argument is not already a list. - - For example: - `dimensionize(3, nd=2)` - will produce the following result: - `(3, 3)`. - `dimensionize([3, 1], nd=2)` - will produce the following result: - `[3, 1]`. - - For more information, refer to: - - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/conv.py - - https://github.com/guillaume-chevalier/python-conv-lib - - MIT License, Copyright (c) 2018 Guillaume Chevalier - """ - if not hasattr(maybe_a_list, '__iter__'): - # Argument is probably an integer so we map it to a list of size `nd`. - now_a_list = [maybe_a_list] * nd - return now_a_list - else: - # Argument is probably an `nd`-sized list. - return maybe_a_list diff --git a/algorithms/matrix/matrix_rotation.txt b/algorithms/matrix/matrix_rotation.txt deleted file mode 100644 index 9ce876e6a..000000000 --- a/algorithms/matrix/matrix_rotation.txt +++ /dev/null @@ -1,580 +0,0 @@ -I'd like to add a little more detail. -In this answer, key concepts are repeated, the pace is slow and intentionally -repetitive. The solution provided here is not the most syntactically compact, -it is however intended for those who wish to learn what matrix rotation is and -the resulting implementation. - -Firstly, what is a matrix? For the purposes of this answer, a matrix is just -a grid where the width and height are the same. Note, the width and height -of a matrix can be different, but for simplicity, this tutorial considers only -matrices with equal width and height -(and yes, matrices is the plural of matrix). -Example matrices are: 2x2, 3x3 or 5x5. Or, more generally, NxN. -A 2x2 matrix will have 4 squares because 2x2=4. -A 5x5 matrix will have 25 squares because 5x5=25. -Each square is called an element or entry. We’ll represent each element with -a period (.) in the diagrams below: - -2x2 matrix - - . . - . . - -3x3 matrix - - . . . - . . . - . . . - -4x4 matrix - - . . . . - . . . . - . . . . - . . . . - - -So, what does it mean to rotate a matrix? Let’s take a 2x2 matrix and -put some numbers in each element so the rotation can be observed: - - 0 1 - 2 3 - -Rotating this by 90 degrees gives us: - - 2 0 - 3 1 - -We literally turned the whole matrix once to the right just like turning the -steering wheel of a car. It may help to think of “tipping” the matrix onto -its right side. We want to write a function, in Python, that takes a matrix and -rotates in once to the right. The function signature will be: - - def rotate(matrix): - # Algorithm goes here. - -The matrix will be defined using a two-dimensional array: - - matrix = [ - [0,1], - [2,3] - ] - -Therefore the first index position accesses the row. -The second index position accesses the column: - - matrix[row][column] - -We’ll define a utility function to print a matrix. - - def print_matrix(matrix): - for row in matrix: - print row - -One method of rotating a matrix is to do it a layer at a time. -But what is a layer? Think of an onion. Just like the layers of an onion, -as each layer is removed, we move towards the center. -ther analogies is a Matryoshka doll or a game of pass-the-parcel. - -The width and height of a matrix dictate the number of layers in that matrix. -Let’s use different symbols for each layer: - -2x2 matrix has 1 layer - - . . - . . - -3x3 matrix has 2 layers - - . . . - . x . - . . . - -4x4 matrix has 2 layers - - . . . . - . x x . - . x x . - . . . . - -5x5 matrix has 3 layers - - . . . . . - . x x x . - . x O x . - . x x x . - . . . . . - -6x6 matrix has 3 layers - - . . . . . . - . x x x x . - . x O O x . - . x O O x . - . x x x x . - . . . . . . - -7x7 matrix has 4 layers - - . . . . . . . - . x x x x x . - . x O O O x . - . x O - O x . - . x O O O x . - . x x x x x . - . . . . . . . - -You may notice that incrementing the width and height of a matrix by one, -does not always increase the number of layers. -Taking the above matrices and tabulating the layers and dimensions, -we see the number of layers increases once for every two increments of -width and height: - - +-----+--------+ - | NxN | Layers | - +-----+--------+ - | 1x1 | 1 | - | 2x2 | 1 | - | 3x3 | 2 | - | 4x4 | 2 | - | 5x5 | 3 | - | 6x6 | 3 | - | 7x7 | 4 | - +-----+--------+ - -However, not all layers need rotating. -A 1x1 matrix is the same before and after rotation. -The central 1x1 layer is always the same before and -after rotation no matter how large the overall matrix: - - +-----+--------+------------------+ - | NxN | Layers | Rotatable Layers | - +-----+--------+------------------+ - | 1x1 | 1 | 0 | - | 2x2 | 1 | 1 | - | 3x3 | 2 | 1 | - | 4x4 | 2 | 2 | - | 5x5 | 3 | 2 | - | 6x6 | 3 | 3 | - | 7x7 | 4 | 3 | - +-----+--------+------------------+ - -Given NxN matrix, how can we programmatically determine the number of layers -we need to rotate? -If we divide the width or height by two and ignore the remainder -we get the following results. - - +-----+--------+------------------+---------+ - | NxN | Layers | Rotatable Layers | N/2 | - +-----+--------+------------------+---------+ - | 1x1 | 1 | 0 | 1/2 = 0 | - | 2x2 | 1 | 1 | 2/2 = 1 | - | 3x3 | 2 | 1 | 3/2 = 1 | - | 4x4 | 2 | 2 | 4/2 = 2 | - | 5x5 | 2 | 2 | 5/2 = 2 | - | 6x6 | 3 | 3 | 6/2 = 3 | - | 7x7 | 4 | 3 | 7/2 = 3 | - +-----+--------+------------------+---------+ - -Notice how N/2 matches the number of layers that need to be rotated? -Sometimes the number of rotatable layers is one less the total number of -layers in the matrix. -This occurs when the innermost layer is formed of only one element -(i.e. a 1x1 matrix) and therefore need not be rotated. It simply gets ignored. - -We will undoubtedly need this information in our function to -rotate a matrix, so let’s add it now: - - def rotate(matrix): - size = len(matrix) - # Rotatable layers only. - layer_count = size / 2 - -Now we know what layers are and how to determine the number of layers -that actually need rotating, how do we isolate a single layer so we can rotate -it? Firstly, we inspect a matrix from the outermost layer, -inwards, to the innermost layer. -A 5x5 matrix has three layers in total and two layers that need rotating: - - . . . . . - . x x x . - . x O x . - . x x x . - . . . . . - -Let’s look at columns first. The position of the columns defining the -outermost layer, assuming we count from 0, are 0 and 4: - - +--------+-----------+ - | Column | 0 1 2 3 4 | - +--------+-----------+ - | | . . . . . | - | | . x x x . | - | | . x O x . | - | | . x x x . | - | | . . . . . | - +--------+-----------+ - -0 and 4 are also the positions of the rows for the outermost layer. - - +-----+-----------+ - | Row | | - +-----+-----------+ - | 0 | . . . . . | - | 1 | . x x x . | - | 2 | . x O x . | - | 3 | . x x x . | - | 4 | . . . . . | - +-----+-----------+ - -This will always be the case since the width and height are the same. -Therefore we can define the column and row positions of a layer with just -two values (rather than four). - -Moving inwards to the second layer, the position of the columns are 1 and 3. -And, yes, you guessed it, it’s the same for rows. -It’s important to understand we had to both increment and decrement the row -and column positions when moving inwards to the next layer. - - +-----------+---------+---------+---------+ - | Layer | Rows | Columns | Rotate? | - +-----------+---------+---------+---------+ - | Outermost | 0 and 4 | 0 and 4 | Yes | - | Inner | 1 and 3 | 1 and 3 | Yes | - | Innermost | 2 | 2 | No | - +-----------+---------+---------+---------+ - -So, to inspect each layer, we want a loop with both increasing and decreasing -counters that represent moving inwards, starting from the outermost layer. -We’ll call this our ‘layer loop’. - - def rotate(matrix): - size = len(matrix) - layer_count = size / 2 - - for layer in range(0, layer_count): - first = layer - last = size - first - 1 - print 'Layer %d: first: %d, last: %d'%(layer, first, last) - - # 5x5 matrix - matrix = [ - [0,1,2,3,4], - [5,6,7,8,9], - [10,11,12,13,14], - [15,16,17,18,19], - [20,21,22,23,24] - ] - - rotate(matrix) - -The code above loops through the (row and column) positions of any layers that need rotating. - - first: 0, last: 4 - first: 1, last: 3 - -We now have a loop providing the positions of the rows and columns of each layer. The variables first and last identify the index position of the first and last rows and columns. Referring back to our row and column tables: - - +--------+-----------+ - | Column | 0 1 2 3 4 | - +--------+-----------+ - | | . . . . . | - | | . x x x . | - | | . x O x . | - | | . x x x . | - | | . . . . . | - +--------+-----------+ - - +-----+-----------+ - | Row | | - +-----+-----------+ - | 0 | . . . . . | - | 1 | . x x x . | - | 2 | . x O x . | - | 3 | . x x x . | - | 4 | . . . . . | - +-----+-----------+ - -So we can navigate through the layers of a matrix. Now we need a way of navigating within a layer so we can move elements around that layer. Note, elements never ‘jump’ from one layer to another, but they do move within their respective layers. - -Rotating each element in a layer rotates the entire layer. Rotating all layers in a matrix rotates the entire matrix. This sentence is very important, so please try your best to understand it before moving on. - -Now, we need a way of actually moving elements, i.e. rotate each element, and subsequently the layer, and ultimately the matrix. For simplicity, we’ll revert to a 3x3 matrix - that has one rotatable layer. - - 0 1 2 - 3 4 5 - 6 7 8 - -Our layer loop provides the indexes of the first and last columns, as well as first and last rows: - - +-----+-------+ - | Col | 0 1 2 | - +-----+-------+ - | | 0 1 2 | - | | 3 4 5 | - | | 6 7 8 | - +-----+-------+ - - +-----+-------+ - | Row | | - +-----+-------+ - | 0 | 0 1 2 | - | 1 | 3 4 5 | - | 2 | 6 7 8 | - +-----+-------+ - -Because our matrices are always square, we need just two variables, first and last, since index positions are the same for rows and columns. - - def rotate(matrix): - size = len(matrix) - layer_count = size / 2 - - # Our layer loop i=0, i=1, i=2 - for layer in range(0, layer_count): - - first = layer - last = size - first - 1 - - # We want to move within a layer here. - -The variables first and last can easily be used to reference the four corners of a matrix. This is because the corners themselves can be defined used various permutations of first and last (with no subtraction, addition or offset of those variables): - - +-----------------+-----------------+-------------+ - | Corner | Position | 3x3 Values | - +-----------------+-----------------+-------------+ - | top left | (first, first) | (0,0) | - | top right | (first, last) | (0,2) | - | bottom right | (last, last) | (2,2) | - | bottom left | (last, first) | (2,0) | - +-----------------+-----------------+-------------+ - -For this reason, we start our rotation at the outer four corners: We’ll rotate those first, let’s highlight them with *. - - * 1 * - 3 4 5 - * 7 * - -We want to swap each *, with the * to the right of it. So let’s go ahead a print out our corners defined using only various permutations of first and last: - - def rotate(matrix): - size = len(matrix) - layer_count = size / 2 - for layer in range(0, layer_count): - - first = layer - last = size - first - 1 - - top_left = (first, first) - top_right = (first, last) - bottom_right = (last, last) - bottom_left = (last, first) - - print 'top_left: %s'%(top_left,) - print 'top_right: %s'%(top_right,) - print 'bottom_right: %s'%(bottom_right,) - print 'bottom_left: %s'%(bottom_left,) - - matrix = [ - [0, 1, 2], - [3, 4, 5], - [6, 7, 8] - ] - - rotate(matrix) - -Output should be: - - top_left: (0, 0) - top_right: (0, 2) - bottom_right: (2, 2) - bottom_left: (2, 0) - -Now we could quite easily swap each of the corners from within our layer loop: - - def rotate(matrix): - size = len(matrix) - layer_count = size / 2 - for layer in range(0, layer_count): - - first = layer - last = size - first - 1 - - top_left = matrix[first][first] - top_right = matrix[first][last] - bottom_right = matrix[last][last] - bottom_left = matrix[last][first] - - # bottom_left -> top_left - matrix[first][first] = bottom_left - # top_left -> top_right - matrix[first][last] = top_left - # top_right -> bottom_right - matrix[last][last] = top_right - # bottom_right -> bottom_left - matrix[last][first] = bottom_right - - - print_matrix(matrix) - print '---------' - rotate(matrix) - print_matrix(matrix) - -Matrix before rotating corners: - - [0, 1, 2] - [3, 4, 5] - [6, 7, 8] - -Matrix after rotating corners: - - [6, 1, 0] - [3, 4, 5] - [8, 7, 2] - -Great! We have successfully rotated each corner of the matrix. But, we haven’t rotated the elements in the middle of each layer. Clearly we need a way of iterating within a layer. - -The problem is, the only loop in our function so far (our layer loop), moves to the next layer on each iteration. Since our matrix has only one rotatable layer, the layer loop exits after rotating only the corners. Let’s look at what happens with a larger, 5x5 matrix (where two layers need rotating). The function code has been omitted, but it remains the same as above: - - matrix = [ - [0, 1, 2, 3, 4] - [5, 6, 7, 8, 9] - [10, 11, 12, 13, 14] - [15, 16, 17, 18, 19] - [20, 21, 22, 23, 24] - ] - print_matrix(matrix) - print '--------------------' - rotate(matrix) - print_matrix(matrix) - -The output is: - - [20, 1, 2, 3, 0 ] - [5, 16, 7, 6, 9 ] - [10, 11, 12, 13, 14] - [15, 18, 17, 8, 19] - [24, 21, 22, 23, 4 ] - -It shouldn’t be a surprise that the corners of the outermost layer have been rotated, but, you may also notice the corners of the next layer (inwards) have also been rotated. This makes sense. We’ve written code to navigate through layers and also to rotate the corners of each layer. This feels like progress, but unfortunately we must take a step back. It’s just no use moving onto the next layer until the previous (outer) layer has been fully rotated. That is, until each element in the layer has been rotated. Rotating only the corners won’t do! - -Take a deep breath. We need another loop. A nested loop no less. The new, nested loop, will use the first and last variables, plus an offset to navigate within a layer. We’ll call this new loop our ‘element loop’. The element loop will visit each element along the top row, each element down the right side, each element along the bottom row and each element up the left side. - - - Moving across the top row requires the column index to be - incremented. - - Moving down the right side requires the row index to be - incremented. - - Moving backwards along the bottom requires the column - index to be decremented. - - Moving up the left side requires the row - index to be decremented. - -This sound complex, but it’s made easy because the number of times we increment and decrement to achieve the above remains the same along all four sides of the matrix. For example: - - - Move 1 element across the top row. - - Move 1 element down the right side. - - Move 1 element backwards along the bottom row. - - Move 1 element up the left side. - -This means we can use a single variable, in combination with the first and last variables to move within a layer. It may help to note that moving across the top row and down the right side both require incrementing. While moving backwards along the bottom and up the left side both require decrementing. - - def rotate(matrix): - size = len(matrix) - layer_count = size / 2 - - # Move through layers (i.e. layer loop). - for layer in range(0, layer_count): - - first = layer - last = size - first - 1 - - # Move within a single layer (i.e. element loop). - for element in range(first, last): - - offset = element - first - - # ‘element’ increments column (across right) - top = (first, element) - # ‘element’ increments row (move down) - right_side = (element, last) - # ‘last-offset’ decrements column (across left) - bottom = (last, last-offset) - # ‘last-offset’ decrements row (move up) - left_side = (last-offset, first) - - print 'top: %s'%(top,) - print 'right_side: %s'%(right_side,) - print 'bottom: %s'%(bottom,) - print 'left_side: %s'%(left_side,) - -Now we simply need to assign the top to the right side, right side to the bottom, bottom to the left side, and left side to the top. Putting this all together we get: - - def rotate(matrix): - size = len(matrix) - layer_count = size / 2 - - for layer in range(0, layer_count): - first = layer - last = size - first - 1 - - for element in range(first, last): - offset = element - first - - top = matrix[first][element] - right_side = matrix[element][last] - bottom = matrix[last][last-offset] - left_side = matrix[last-offset][first] - - matrix[first][element] = left_side - matrix[element][last] = top - matrix[last][last-offset] = right_side - matrix[last-offset][first] = bottom - -Given the matrix: - - 0, 1, 2 - 3, 4, 5 - 6, 7, 8 - -Our rotate function results in: - - 6, 3, 0 - 7, 4, 1 - 8, 5, 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/algorithms/union-find/count_islands.py b/algorithms/unionfind/count_islands.py similarity index 100% rename from algorithms/union-find/count_islands.py rename to algorithms/unionfind/count_islands.py diff --git a/tests/test_graph.py b/tests/test_graph.py index 73ef23057..c691f33d2 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -8,6 +8,7 @@ from algorithms.graph import maximum_flow_dfs from algorithms.graph import all_pairs_shortest_path from algorithms.graph import bellman_ford +from algorithms.graph import bellman_ford import unittest diff --git a/tests/test_iterables.py b/tests/test_iterables.py deleted file mode 100644 index 4e23d850e..000000000 --- a/tests/test_iterables.py +++ /dev/null @@ -1,161 +0,0 @@ -from algorithms.iterables import ( - convolved_1d, convolved_2d -) - -import itertools -import unittest - - -class TestConvolved1D(unittest.TestCase): - """Tests copied from: - - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/tests/test_convolved_1d.py - - MIT License, Copyright (c) 2018 Guillaume Chevalier - """ - - def test_trivial_loop(self): - expected = tuple(range(7)) - result = [] - - for kernel_hover in convolved_1d(expected, kernel_size=1, padding=0, stride=1): - result.append(*kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_for_with_stride_two(self): - expected = tuple(range(0, 7, 2)) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=1, padding=0, stride=2): - result.append(*kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_for_with_padding_one(self): - expected = tuple([42] + list(range(0, 7)) + [42]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=1, padding=1, stride=1, default_value=42): - result.append(*kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_two(self): - expected = tuple([a, b] for a, b in zip(list(range(0, 6)), list(range(1, 7)))) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=0, stride=1): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_two_and_stride_two(self): - expected = ([0, 1], [2, 3], [4, 5], [6, None]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=0, stride=2): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_two_and_stride_two_and_padding_two(self): - expected = ([None, None], [0, 1], [2, 3], [4, 5], [6, None], [None, None]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=2, stride=2): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_two_and_stride_two_and_padding_three(self): - expected = ([None, None], [None, 0], [1, 2], [3, 4], [5, 6], [None, None], [None, None]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=3, stride=2): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_three_and_stride_two_and_padding_two(self): - expected = ([None, None, 0], [0, 1, 2], [2, 3, 4], [4, 5, 6], [6, None, None]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=3, padding=2, stride=2): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_two_and_stride_three_and_padding_two(self): - expected = ([None, None], [1, 2], [4, 5], [None, None]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=2, padding=2, stride=3): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_seven_kernel_of_three_and_stride_three_and_padding_three(self): - expected = ([None, None, None], [0, 1, 2], [3, 4, 5], [6, None, None], [None, None, None]) - result = [] - - for kernel_hover in convolved_1d(list(range(7)), kernel_size=3, padding=3, stride=3): - result.append(kernel_hover) - result = tuple(result) - - self.assertEqual(expected, result) - - -class TestConvolved2D(unittest.TestCase): - """Tests copied from: - - https://github.com/guillaume-chevalier/python-conv-lib/blob/master/conv/tests/test_convolved_1d.py - - MIT License, Copyright (c) 2018 Guillaume Chevalier - """ - - def test_trivial_1x1_loop(self): - base = tuple(tuple(range(i ** 2, 7 + i ** 2)) for i in range(7)) - expected = tuple(([i],) for i in itertools.chain(*base)) - result = [] - - for kernel_hover in convolved_2d(base, kernel_size=1, padding=0, stride=1): - result.append(tuple(kernel_hover)) - result = tuple(result) - - self.assertEqual(expected, result) - - def test_simple_2x2_loop_on_3x2(self): - base = [ - [1, 2], - [3, 4], - [5, 6] - ] - expected = ( - ( - [1, 2], - [3, 4] - ), ( - [3, 4], - [5, 6] - ) - ) - result = [] - - for kernel_hover in convolved_2d(base, kernel_size=2, padding=0, stride=1): - result.append(tuple(kernel_hover)) - result = tuple(result) - - print(result) - print(expected) - - self.assertEqual(expected, result) - - -if __name__ == "__main__": - unittest.main() From 716c78740a5a10b0456262a9ea249aec07957ffb Mon Sep 17 00:00:00 2001 From: overkill <22098433+0verk1ll@users.noreply.github.com> Date: Sun, 12 Jan 2020 05:57:45 +0000 Subject: [PATCH 197/302] Removed Unused Var `carry` in multiply_srings.py (#628) * Fix problems with testing equality to None. * Removed unused variable --- algorithms/automata/dfa.py | 11 +++++------ algorithms/graph/tarjan.py | 8 ++++---- algorithms/strings/multiply_strings.py | 3 +-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/algorithms/automata/dfa.py b/algorithms/automata/dfa.py index 36211c7e8..34f73a4b4 100644 --- a/algorithms/automata/dfa.py +++ b/algorithms/automata/dfa.py @@ -3,16 +3,15 @@ def DFA(transitions, start, final, string): num = len(string) num_final = len(final) cur = start - - for i in range (num): - - if transitions[cur][string[i]] == None: + + for i in range(num): + + if transitions[cur][string[i]] is None: return False else: cur = transitions[cur][string[i]] - for i in range (num_final): + for i in range(num_final): if cur == final[i]: return True return False - diff --git a/algorithms/graph/tarjan.py b/algorithms/graph/tarjan.py index a2f44e58d..399a39d6d 100644 --- a/algorithms/graph/tarjan.py +++ b/algorithms/graph/tarjan.py @@ -5,6 +5,7 @@ """ from algorithms.graph.graph import DirectedGraph + class Tarjan(object): def __init__(self, dict_graph): self.graph = DirectedGraph(dict_graph) @@ -18,7 +19,7 @@ def __init__(self, dict_graph): self.sccs = [] for v in self.graph.nodes: - if v.index == None: + if v.index is None: self.strongconnect(v, self.sccs) def strongconnect(self, v, sccs): @@ -31,7 +32,7 @@ def strongconnect(self, v, sccs): # Consider successors of v for w in self.graph.adjmt[v]: - if w.index == None: + if w.index is None: # Successor w has not yet been visited; recurse on it self.strongconnect(w, sccs) v.lowlink = min(v.lowlink, w.lowlink) @@ -41,7 +42,7 @@ def strongconnect(self, v, sccs): # Note: The next line may look odd - but is correct. # It says w.index not w.lowlink; that is deliberate and from the original paper v.lowlink = min(v.lowlink, w.index) - + # If v is a root node, pop the stack and generate an SCC if v.lowlink == v.index: # start a new strongly connected component @@ -54,4 +55,3 @@ def strongconnect(self, v, sccs): break scc.sort() sccs.append(scc) - diff --git a/algorithms/strings/multiply_strings.py b/algorithms/strings/multiply_strings.py index 0ddc3abf4..2cb0d2206 100644 --- a/algorithms/strings/multiply_strings.py +++ b/algorithms/strings/multiply_strings.py @@ -12,8 +12,7 @@ """ -def multiply(num1:"str", num2:"str")->"str": - carry = 1 +def multiply(num1: "str", num2: "str") -> "str": interm = [] zero = ord('0') i_pos = 1 From 38173ae71780f0cb7f44373867a2ec559b239056 Mon Sep 17 00:00:00 2001 From: overkill <22098433+0verk1ll@users.noreply.github.com> Date: Sun, 12 Jan 2020 05:58:04 +0000 Subject: [PATCH 198/302] Fix problems with testing equality to None. (#627) From ebc8de44dbc17608155f110723d17df14a21c305 Mon Sep 17 00:00:00 2001 From: siderism Date: Thu, 13 Feb 2020 07:25:56 +0200 Subject: [PATCH 199/302] Add sum of sub squares of a given nxn matrix (#631) * Added function to calculate sum of all sub-squares in a square matrix * Added test for sum_sub_squares function * Updated README --- README.md | 1 + algorithms/matrix/sum_sub_squares.py | 24 ++++++++++++++++++++++++ tests/test_matrix.py | 18 +++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 algorithms/matrix/sum_sub_squares.py diff --git a/README.md b/README.md index 53b8c691d..61daf4e8f 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,7 @@ If you want to uninstall algorithms, it is as simple as: - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py) - [cholesky_matrix_decomposition](algorithms/matrix/cholesky_matrix_decomposition.py) + - [sum_sub_squares](algorithms/matrix/sum_sub_squares.py) - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) diff --git a/algorithms/matrix/sum_sub_squares.py b/algorithms/matrix/sum_sub_squares.py new file mode 100644 index 000000000..45de7f10c --- /dev/null +++ b/algorithms/matrix/sum_sub_squares.py @@ -0,0 +1,24 @@ +# Function to find sum of all +# sub-squares of size k x k in a given +# square matrix of size n x n +def sum_sub_squares(matrix, k): + n = len(matrix) + result = [[0 for i in range(k)] for j in range(k)] + + if k > n: + return + for i in range(n - k + 1): + l = 0 + for j in range(n - k + 1): + sum = 0 + + # Calculate and print sum of current sub-square + for p in range(i, k + i): + for q in range(j, k + j): + sum += matrix[p][q] + + result[i][l] = sum + l += 1 + + return result + diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 3522d7dc7..ad49dddc0 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -7,7 +7,8 @@ rotate_image, sparse_dot_vector, spiral_traversal, - sudoku_validator + sudoku_validator, + sum_sub_squares ) import unittest @@ -272,6 +273,21 @@ def test_sudoku_validator(self): [3, 0, 0, 4, 8, 1, 1, 7, 9] ])) +class TestSumSubSquares(unittest.TestCase): + """[summary] + Test for the file sum_sub_squares.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_sum_sub_squares(self): + mat = [[1, 1, 1, 1, 1], + [2, 2, 2, 2, 2], + [3, 3, 3, 3, 3], + [4, 4, 4, 4, 4], + [5, 5, 5, 5, 5]] + self.assertEqual(sum_sub_squares.sum_sub_squares(mat, 3), + [[18, 18, 18], [27, 27, 27], [36, 36, 36]]) if __name__ == "__main__": unittest.main() From 5f9838d5f6fa3b206ed1e24cc510df25908f86a8 Mon Sep 17 00:00:00 2001 From: Johan von Hacht Date: Wed, 26 Feb 2020 21:53:01 +0100 Subject: [PATCH 200/302] Add two more breaking bad tests (#636) * Add two more breaking bad tests * move tests to test_bracket --- tests/test_strings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_strings.py b/tests/test_strings.py index b20de80e6..48fafd2a5 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -79,7 +79,8 @@ def test_match_symbol_1(self): def test_bracket(self): self.assertEqual(('[Am]azon', 'Mi[cro]soft', 'Goog[le]'), bracket(self.words, self.symbols)) - + self.assertEqual(('Amazon', 'Microsoft', 'Google'), bracket(self.words, ['thisshouldnotmatch'])) + self.assertEqual(('Amazon', 'M[i]crosoft', 'Google'), bracket(self.words, ['i', 'i'])) class TestDecodeString(unittest.TestCase): """[summary] From ac1718e16d83203dec6d3214690c84117d50d022 Mon Sep 17 00:00:00 2001 From: Amanda Bertsch <42593540+abertsch72@users.noreply.github.com> Date: Wed, 26 Feb 2020 13:54:38 -0700 Subject: [PATCH 201/302] Add matrix inversion (#582) * adds matrix inversion for n x n matrices * adds link in readme and edge cases in file * fixes typo --- README.md | 1 + algorithms/matrix/matrix_inversion.py | 124 ++++++++++++++++++++++++++ tests/test_matrix.py | 32 +++++++ 3 files changed, 157 insertions(+) create mode 100644 algorithms/matrix/matrix_inversion.py diff --git a/README.md b/README.md index 61daf4e8f..90a062f29 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ If you want to uninstall algorithms, it is as simple as: - [copy_transform](algorithms/matrix/copy_transform.py) - [count_paths](algorithms/matrix/count_paths.py) - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) + - [matrix_inversion](algorithms/matrix/matrix_inversion.py) - [matrix_multiplication](algorithms/matrix/multiply.py) - [rotate_image](algorithms/matrix/rotate_image.py) - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) diff --git a/algorithms/matrix/matrix_inversion.py b/algorithms/matrix/matrix_inversion.py new file mode 100644 index 000000000..7dfb093ff --- /dev/null +++ b/algorithms/matrix/matrix_inversion.py @@ -0,0 +1,124 @@ +""" +Inverts an invertible n x n matrix -- i.e., given an n x n matrix A, returns +an n x n matrix B such that AB = BA = In, the n x n identity matrix. + +For a 2 x 2 matrix, inversion is simple using the cofactor equation. For +larger matrices, this is a four step process: +1. calculate the matrix of minors: create an n x n matrix by considering each +position in the original matrix in turn. Exclude the current row and column +and calculate the determinant of the remaining matrix, then place that value +in the current position's equivalent in the matrix of minors. +2. create the matrix of cofactors: take the matrix of minors and multiply +alternate values by -1 in a checkerboard pattern. +3. adjugate: hold the top left to bottom right diagonal constant, but swap all +other values over it. +4. multiply the adjugated matrix by 1 / the determinant of the original matrix + +This code combines steps 1 and 2 into one method to reduce traversals of the +matrix. + +Possible edge cases: will not work for 0x0 or 1x1 matrix, though these are +trivial to calculate without use of this file. +""" +import fractions + + +def invert_matrix(m): + """invert an n x n matrix""" + # Error conditions + if not array_is_matrix(m): + print("Invalid matrix: array is not a matrix") + return [[-1]]; + elif len(m) != len(m[0]): + print("Invalid matrix: matrix is not square") + return [[-2]]; + elif len(m) < 2: + print("Invalid matrix: matrix is too small") + return [[-3]]; + elif get_determinant(m) == 0: + print("Invalid matrix: matrix is square, but singular (determinant = 0)") + return [[-4]]; + + # Calculation + elif len(m) == 2: + # simple case + multiplier = 1 / get_determinant(m) + inverted = [[multiplier] * len(m) for n in range(len(m))] + inverted[0][1] = inverted[0][1] * -1 * m[0][1] + inverted[1][0] = inverted[1][0] * -1 * m[1][0] + inverted[0][0] = multiplier * m[1][1] + inverted[1][1] = multiplier * m[0][0] + return inverted + else: + """some steps combined in helpers to reduce traversals""" + # get matrix of minors w/ "checkerboard" signs + m_of_minors = get_matrix_of_minors(m) + + # calculate determinant (we need to know 1/det) + multiplier = fractions.Fraction(1, get_determinant(m)) + + # adjugate (swap on diagonals) and multiply by 1/det + inverted = transpose_and_multiply(m_of_minors, multiplier) + + return inverted + + +def get_determinant(m): + """recursively calculate the determinant of an n x n matrix, n >= 2""" + if len(m) == 2: + # trivial case + return (m[0][0] * m[1][1]) - (m[0][1] * m[1][0]) + else: + sign = 1 + det = 0 + for i in range(len(m)): + det += sign * m[0][i] * get_determinant(get_minor(m, 0, i)) + sign *= -1 + return det + + +def get_matrix_of_minors(m): + """get the matrix of minors and alternate signs""" + matrix_of_minors = [[0 for i in range(len(m))] for j in range(len(m))] + for row in range(len(m)): + for col in range(len(m[0])): + if (row + col) % 2 == 0: + sign = 1 + else: + sign = -1 + matrix_of_minors[row][col] = sign * get_determinant(get_minor(m, row, col)) + return matrix_of_minors + + +def get_minor(m, row, col): + """ + get the minor of the matrix position m[row][col] + (all values m[r][c] where r != row and c != col) + """ + minors = [] + for i in range(len(m)): + if i != row: + new_row = m[i][:col] + new_row.extend(m[i][col + 1:]) + minors.append(new_row) + return minors + + +def transpose_and_multiply(m, multiplier=1): + """swap values along diagonal, optionally adding multiplier""" + for row in range(len(m)): + for col in range(row + 1): + temp = m[row][col] * multiplier + m[row][col] = m[col][row] * multiplier + m[col][row] = temp + return m + + +def array_is_matrix(m): + if len(m) == 0: + return False + first_col = len(m[0]) + for row in m: + if len(row) != first_col: + return False + return True diff --git a/tests/test_matrix.py b/tests/test_matrix.py index ad49dddc0..da041e027 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -3,6 +3,7 @@ copy_transform, crout_matrix_decomposition, cholesky_matrix_decomposition, + matrix_inversion, multiply, rotate_image, sparse_dot_vector, @@ -127,6 +128,37 @@ def test_cholesky_matrix_decomposition(self): [[5, 1.2, 0.3, -0.6], [1.2, 6, -0.4, 0.9], [0.3, -0.4, 8, 1.7], [-0.6, 0.9, 1.7, 10]])) +class TestInversion(unittest.TestCase): + """[summary] + Test for the file matrix_inversion.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_inversion(self): + from fractions import Fraction + + m1 = [[1, 1], [1, 2]] + self.assertEqual(matrix_inversion.invert_matrix(m1), [[2, -1], [-1, 1]]) + + m2 = [[1, 2], [3, 4, 5]] + self.assertEqual(matrix_inversion.invert_matrix(m2), [[-1]]) + + m3 = [[1, 1, 1, 1], [2, 2, 2, 2]] + self.assertEqual(matrix_inversion.invert_matrix(m3), [[-2]]) + + m4 = [[1]] + self.assertEqual(matrix_inversion.invert_matrix(m4), [[-3]]) + + m5 = [[1, 2, 3] , [4, 5, 6], [7, 8, 9]] + self.assertEqual(matrix_inversion.invert_matrix(m5), [[-4]]) + + m6 = [[3, 5, 1], [2, 5, 0], [1, 9, 8]] + self.assertEqual(matrix_inversion.invert_matrix(m6), [[Fraction(40, 53), Fraction(-31, 53), Fraction(-5, 53)], + [Fraction(-16, 53), Fraction(23, 53), Fraction(2, 53)], + [Fraction(13, 53), Fraction(-22, 53), Fraction(5, 53)]]) + + class TestMultiply(unittest.TestCase): """[summary] From 4ecdba1ebb3ec42c6da7156ba94f32143cd37ffc Mon Sep 17 00:00:00 2001 From: Hardik dadhich Date: Wed, 4 Mar 2020 00:13:20 +0530 Subject: [PATCH 202/302] Find Total Number of Connected Component in Graph --- .../count_connected_number_of_component.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 algorithms/graph/count_connected_number_of_component.py diff --git a/algorithms/graph/count_connected_number_of_component.py b/algorithms/graph/count_connected_number_of_component.py new file mode 100644 index 000000000..19caec45a --- /dev/null +++ b/algorithms/graph/count_connected_number_of_component.py @@ -0,0 +1,54 @@ +#count connected no of component using DFS +''' +In graph theory, a component, sometimes called a connected component, +of an undirected graph is a subgraph in which any +two vertices are connected to each other by paths. + +Example: + + + 1 3------------7 + | + | + 2--------4 + | | + | | output = 2 + 6--------5 + +''' + +# Code is Here + +def dfs(source,visited): + ''' Function that performs DFS ''' + + visited[source] = True + for child in l[source]: + if not visited[child]: + dfs(child,visited) + +def count_components(l,size): + ''' + Function that counts the Connected components on bases of DFS. + return type : int + ''' + + count = 0 + visited = [False]*(size+1) + for i in range(1,size+1): + if not visited[i]: + dfs(i,visited) + count+=1 + return count + + +# Driver code +if __name__ == '__main__': + n,m = map(int, input("Enter the Number of Nodes and Edges \n").split(' ')) + l = [[] for _ in range(n+1)] + for i in range(m): + print("Enter the edge's Nodes in form of a b\n") + a,b = map(int,input().split(' ')) + l[a].append(b) + l[b].append(a) + print("Total number of Connected Components are : ", count_components(l,n)) From c117e195f0fe51b0d36754f842b32ca352b14af1 Mon Sep 17 00:00:00 2001 From: Hardik dadhich Date: Sat, 7 Mar 2020 14:02:19 +0530 Subject: [PATCH 203/302] Added unit tests --- README.md | 1 + .../count_connected_number_of_component.py | 8 ++-- tests/test_count_connected_components.py | 37 +++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 tests/test_count_connected_components.py diff --git a/README.md b/README.md index 90a062f29..06fb2d4c4 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ If you want to uninstall algorithms, it is as simple as: - [maximum_flow_dfs](algorithms/graph/maximum_flow_dfs.py) - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) - [bellman_ford](algorithms/graph/bellman_ford.py) + - [Count Connected Components](algoritms/graph/count_connected_number_of_component.py) - [heap](algorithms/heap) - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - [skyline](algorithms/heap/skyline.py) diff --git a/algorithms/graph/count_connected_number_of_component.py b/algorithms/graph/count_connected_number_of_component.py index 19caec45a..a944cf096 100644 --- a/algorithms/graph/count_connected_number_of_component.py +++ b/algorithms/graph/count_connected_number_of_component.py @@ -19,13 +19,13 @@ # Code is Here -def dfs(source,visited): +def dfs(source,visited,l): ''' Function that performs DFS ''' visited[source] = True for child in l[source]: if not visited[child]: - dfs(child,visited) + dfs(child,visited,l) def count_components(l,size): ''' @@ -37,11 +37,11 @@ def count_components(l,size): visited = [False]*(size+1) for i in range(1,size+1): if not visited[i]: - dfs(i,visited) + dfs(i,visited,l) count+=1 return count - + # Driver code if __name__ == '__main__': n,m = map(int, input("Enter the Number of Nodes and Edges \n").split(' ')) diff --git a/tests/test_count_connected_components.py b/tests/test_count_connected_components.py new file mode 100644 index 000000000..4348ab088 --- /dev/null +++ b/tests/test_count_connected_components.py @@ -0,0 +1,37 @@ +import unittest +from algorithms.graph import count_connected_number_of_component + +class TestConnectedComponentInGraph(unittest.TestCase): + """ Class """ + + def test_count_connected_components(self): + """ + Test Function that test the different cases of count connected components + + 0----------2 1--------5 3 + | + | + 4 + + output = 3 + + """ + expected_result = 3 + l = [[2], + [5], + [0,4], + [], + [2], + [1] + ] + + size = 5 + result = count_connected_number_of_component.count_components(l,size) + self.assertEqual(result,expected_result) + +if __name__ == '__main__': + + unittest.main() + + + From 25da9ad92062537d5f98e8e2aa6db1f16e7d8c56 Mon Sep 17 00:00:00 2001 From: Hardik dadhich Date: Sat, 7 Mar 2020 14:05:57 +0530 Subject: [PATCH 204/302] fixing spaces --- tests/test_count_connected_components.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/test_count_connected_components.py b/tests/test_count_connected_components.py index 4348ab088..b9b1620c5 100644 --- a/tests/test_count_connected_components.py +++ b/tests/test_count_connected_components.py @@ -1,22 +1,25 @@ +#import modules import unittest from algorithms.graph import count_connected_number_of_component class TestConnectedComponentInGraph(unittest.TestCase): - """ Class """ + """ Class to performs unit tests """ def test_count_connected_components(self): """ Test Function that test the different cases of count connected components - 0----------2 1--------5 3 - | - | - 4 - - output = 3 + 0----------2 1--------5 3 + | + | + 4 + + output = 3 """ expected_result = 3 + + # adjacency list representation of graph l = [[2], [5], [0,4], From e5c4699cccbc9b5e02afa8c03b7b098bcef548c8 Mon Sep 17 00:00:00 2001 From: Hardik dadhich Date: Sat, 7 Mar 2020 14:08:12 +0530 Subject: [PATCH 205/302] fixing spaces --- tests/test_count_connected_components.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_count_connected_components.py b/tests/test_count_connected_components.py index b9b1620c5..a7e1fec6d 100644 --- a/tests/test_count_connected_components.py +++ b/tests/test_count_connected_components.py @@ -9,7 +9,7 @@ def test_count_connected_components(self): """ Test Function that test the different cases of count connected components - 0----------2 1--------5 3 + 0----------2 1--------5 3 | | 4 From 9034015aafb6d05202b434f897c9340f1817ecfa Mon Sep 17 00:00:00 2001 From: Hardik dadhich Date: Fri, 13 Mar 2020 01:36:36 +0530 Subject: [PATCH 206/302] adding more unit-tests --- tests/test_count_connected_components.py | 40 ----------------- tests/test_graph.py | 56 +++++++++++++++++++++++- 2 files changed, 54 insertions(+), 42 deletions(-) delete mode 100644 tests/test_count_connected_components.py diff --git a/tests/test_count_connected_components.py b/tests/test_count_connected_components.py deleted file mode 100644 index a7e1fec6d..000000000 --- a/tests/test_count_connected_components.py +++ /dev/null @@ -1,40 +0,0 @@ -#import modules -import unittest -from algorithms.graph import count_connected_number_of_component - -class TestConnectedComponentInGraph(unittest.TestCase): - """ Class to performs unit tests """ - - def test_count_connected_components(self): - """ - Test Function that test the different cases of count connected components - - 0----------2 1--------5 3 - | - | - 4 - - output = 3 - - """ - expected_result = 3 - - # adjacency list representation of graph - l = [[2], - [5], - [0,4], - [], - [2], - [1] - ] - - size = 5 - result = count_connected_number_of_component.count_components(l,size) - self.assertEqual(result,expected_result) - -if __name__ == '__main__': - - unittest.main() - - - diff --git a/tests/test_graph.py b/tests/test_graph.py index c691f33d2..b12646a0e 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -9,7 +9,7 @@ from algorithms.graph import all_pairs_shortest_path from algorithms.graph import bellman_ford from algorithms.graph import bellman_ford - +from algorithms.graph import count_connected_number_of_component import unittest @@ -208,4 +208,56 @@ def test_bellman_ford(self): 'e': {'a': 7, 'b': 5, 'd': 1} } - self.assertEqual(True, bellman_ford(graph2, 'a')) +class TestConnectedComponentInGraph(unittest.TestCase): + """ + Class for testing different cases for connected components in graph + """ + def test_count_connected_components(self): + """ + Test Function that test the different cases of count connected components + + 0----------2 1--------5 3 + | + | + 4 + + output = 3 + """ + expected_result = 3 + + # adjacency list representation of graph + l = [[2], + [5], + [0,4], + [], + [2], + [1] + ] + + size = 5 + result = count_connected_number_of_component.count_components(l,size) + self.assertEqual(result,expected_result) + + def test_connected_components_with_empty_graph(self): + + """ + input : + output : 0 + """ + + l = [[]] + expected_result = 0 + size = 0 + result = count_connected_number_of_component.count_components(l,size) + self.assertEqual(result,expected_result) + + def test_connected_components_without_edges_graph(self): + """ + input : 0 2 3 4 + output : 4 + """ + l = [[0],[],[2],[3],[4]] + size = 4 + expected_result = 4 + result = count_connected_number_of_component.count_components(l,size) + self.assertEqual(result,expected_result) From ae3824422eac2ba796ad117fd7f8f77a5bb9e08b Mon Sep 17 00:00:00 2001 From: Hardik dadhich Date: Fri, 13 Mar 2020 10:10:50 +0530 Subject: [PATCH 207/302] adding line which is deleted --- tests/test_graph.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_graph.py b/tests/test_graph.py index b12646a0e..b9794edf0 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -208,6 +208,9 @@ def test_bellman_ford(self): 'e': {'a': 7, 'b': 5, 'd': 1} } + self.assertEqual(True, bellman_ford(graph2, 'a')) + + class TestConnectedComponentInGraph(unittest.TestCase): """ Class for testing different cases for connected components in graph From 7cdd4170947e39a8d206b4b329f18140a66413bb Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 13 Mar 2020 23:41:17 +0800 Subject: [PATCH 208/302] Remove temporary variable --- algorithms/dp/house_robber.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/algorithms/dp/house_robber.py b/algorithms/dp/house_robber.py index a2a8a6d92..5a359f93d 100644 --- a/algorithms/dp/house_robber.py +++ b/algorithms/dp/house_robber.py @@ -15,7 +15,5 @@ def house_robber(houses): last, now = 0, 0 for house in houses: - tmp = now - now = max(last + house, now) - last = tmp + last, now = now, max(last + house, now) return now From 599144db8849d2bb30e64b4c26f12583225340bf Mon Sep 17 00:00:00 2001 From: Erick Lara Date: Tue, 17 Mar 2020 00:07:40 -0600 Subject: [PATCH 209/302] Small fix on the test description to match the code --- tests/test_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_graph.py b/tests/test_graph.py index b9794edf0..83d35293b 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -219,7 +219,7 @@ def test_count_connected_components(self): """ Test Function that test the different cases of count connected components - 0----------2 1--------5 3 + 2----------0 1--------5 3 | | 4 From 4a7234d4592166a1a13bc6b8e8b3b201019df23b Mon Sep 17 00:00:00 2001 From: Himanshu Airan <62210670+Himanshu-77@users.noreply.github.com> Date: Wed, 13 May 2020 18:30:57 +0530 Subject: [PATCH 210/302] Create prims_minimum_spanning.py code implemented for Prim's Algorithm to find minimum spanning tree. Although there was file named minimum_spanning_tree.py in graph section but contain only Kruskal Algorithm . Prim's Algo. was still missing --- algorithms/graph/prims_minimum_spanning.py | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 algorithms/graph/prims_minimum_spanning.py diff --git a/algorithms/graph/prims_minimum_spanning.py b/algorithms/graph/prims_minimum_spanning.py new file mode 100644 index 000000000..adb31910c --- /dev/null +++ b/algorithms/graph/prims_minimum_spanning.py @@ -0,0 +1,36 @@ +import heapq # for priority queue + +# input number of nodes and edges in graph +n, e = map (int,input().split()) + +# initializing empty graph as a dictionary (of the form {int:list}) +g = dict (zip ([i for i in range(1,n+1)],[[] for i in range(n)])) + +# input graph data +for i in range(e): + a, b, c = map (int,input().split()) + g[a].append([c,b]) + g[b].append([c,a]) + +vis = [] +s = [[0,1]] +prim = [] +mincost = 0 + +# prim's algo. to find weight of minimum spanning tree +while (len(s)>0): + v = heapq.heappop(s) + x = v[1] + if (x in vis): + continue + + mincost += v[0] + prim.append(x) + vis.append(x) + + for j in g[x]: + i = j[-1] + if(i not in vis): + heapq.heappush(s,j) + +print(mincost) From d7ceafc0497022276521f42e5686b0361f73f7fe Mon Sep 17 00:00:00 2001 From: Himanshu Airan <62210670+Himanshu-77@users.noreply.github.com> Date: Wed, 13 May 2020 22:29:53 +0530 Subject: [PATCH 211/302] Update prims_minimum_spanning.py function and sample test cases added --- algorithms/graph/prims_minimum_spanning.py | 90 ++++++++++++++-------- 1 file changed, 59 insertions(+), 31 deletions(-) diff --git a/algorithms/graph/prims_minimum_spanning.py b/algorithms/graph/prims_minimum_spanning.py index adb31910c..060235eac 100644 --- a/algorithms/graph/prims_minimum_spanning.py +++ b/algorithms/graph/prims_minimum_spanning.py @@ -1,36 +1,64 @@ import heapq # for priority queue -# input number of nodes and edges in graph -n, e = map (int,input().split()) +# prim's algo. to find weight of minimum spanning tree +def prims(graph): + vis=[] + s=[[0,1]] + prim = [] + mincost=0 + + while(len(s)>0): + v=heapq.heappop(s) + x=v[1] + if(x in vis): + continue -# initializing empty graph as a dictionary (of the form {int:list}) -g = dict (zip ([i for i in range(1,n+1)],[[] for i in range(n)])) + mincost += v[0] + prim.append(x) + vis.append(x) -# input graph data -for i in range(e): - a, b, c = map (int,input().split()) - g[a].append([c,b]) - g[b].append([c,a]) - -vis = [] -s = [[0,1]] -prim = [] -mincost = 0 + for j in g[x]: + i=j[-1] + if(i not in vis): + heapq.heappush(s,j) -# prim's algo. to find weight of minimum spanning tree -while (len(s)>0): - v = heapq.heappop(s) - x = v[1] - if (x in vis): - continue - - mincost += v[0] - prim.append(x) - vis.append(x) - - for j in g[x]: - i = j[-1] - if(i not in vis): - heapq.heappush(s,j) - -print(mincost) + return mincost + + + +if __name__=="__main__": + + # input number of nodes and edges in graph + n,e = map(int,input().split()) + + # initializing empty graph as a dictionary (of the form {int:list}) + g=dict(zip([i for i in range(1,n+1)],[[] for i in range(n)])) + + # input graph data + for i in range(e): + a,b,c=map(int,input().split()) + g[a].append([c,b]) + g[b].append([c,a]) + + # print weight of minimum spanning tree + print(prims(g)) + + ''' tests- + Input : 4 5 + 1 2 7 + 1 4 6 + 2 4 9 + 4 3 8 + 2 3 6 + Output : 19 + + + Input : 5 6 + 1 2 3 + 1 3 8 + 2 4 5 + 3 4 2 + 3 5 4 + 4 5 6 + Output : 14 + ''' From 52d835ec8a3dfec53c3cab23598be6f63da9addc Mon Sep 17 00:00:00 2001 From: Himanshu Airan <62210670+Himanshu-77@users.noreply.github.com> Date: Thu, 14 May 2020 15:24:30 +0530 Subject: [PATCH 212/302] Update prims_minimum_spanning.py function created --- algorithms/graph/prims_minimum_spanning.py | 60 +++++++--------------- 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/algorithms/graph/prims_minimum_spanning.py b/algorithms/graph/prims_minimum_spanning.py index 060235eac..7e290d81a 100644 --- a/algorithms/graph/prims_minimum_spanning.py +++ b/algorithms/graph/prims_minimum_spanning.py @@ -1,7 +1,24 @@ +''' +This Prim's Algorithm Code is for finding weight of minimum spanning tree +of a connected graph. +For argument graph, it should be a dictionary type +such as +graph = { + 'a': [ [3, 'b'], [8,'c'] ], + 'b': [ [3, 'a'], [5, 'd'] ], + 'c': [ [8, 'a'], [2, 'd'], [4, 'e'] ], + 'd': [ [5, 'b'], [2, 'c'], [6, 'e'] ], + 'e': [ [4, 'c'], [6, 'd'] ] +} + +where 'a','b','c','d','e' are nodes (these can be 1,2,3,4,5 as well) +''' + + import heapq # for priority queue # prim's algo. to find weight of minimum spanning tree -def prims(graph): +def prims(graph_used): vis=[] s=[[0,1]] prim = [] @@ -17,48 +34,9 @@ def prims(graph): prim.append(x) vis.append(x) - for j in g[x]: + for j in graph_used[x]: i=j[-1] if(i not in vis): heapq.heappush(s,j) return mincost - - - -if __name__=="__main__": - - # input number of nodes and edges in graph - n,e = map(int,input().split()) - - # initializing empty graph as a dictionary (of the form {int:list}) - g=dict(zip([i for i in range(1,n+1)],[[] for i in range(n)])) - - # input graph data - for i in range(e): - a,b,c=map(int,input().split()) - g[a].append([c,b]) - g[b].append([c,a]) - - # print weight of minimum spanning tree - print(prims(g)) - - ''' tests- - Input : 4 5 - 1 2 7 - 1 4 6 - 2 4 9 - 4 3 8 - 2 3 6 - Output : 19 - - - Input : 5 6 - 1 2 3 - 1 3 8 - 2 4 5 - 3 4 2 - 3 5 4 - 4 5 6 - Output : 14 - ''' From 581be000530d67b38038d140c457308ee0afd319 Mon Sep 17 00:00:00 2001 From: Himanshu Airan <62210670+Himanshu-77@users.noreply.github.com> Date: Thu, 14 May 2020 15:42:16 +0530 Subject: [PATCH 213/302] Update test_graph.py unittest added for prims_minimum_spanning.py --- tests/test_graph.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_graph.py b/tests/test_graph.py index 83d35293b..325b5d896 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -10,6 +10,7 @@ from algorithms.graph import bellman_ford from algorithms.graph import bellman_ford from algorithms.graph import count_connected_number_of_component +from algorithms.graph import prims_minimum_spanning import unittest @@ -264,3 +265,23 @@ def test_connected_components_without_edges_graph(self): expected_result = 4 result = count_connected_number_of_component.count_components(l,size) self.assertEqual(result,expected_result) + + +class PrimsMinimumSpanning(unittest.TestCase): + def test_prim_spanning(self): + graph1 = { + 1 : [ [3, 2], [8, 3] ], + 2 : [ [3, 1], [5, 4] ], + 3 : [ [8, 1], [2, 4], [4, 5] ], + 4 : [ [5, 2], [2, 3], [6, 5] ], + 5 : [ [4, 3], [6, 4] ] + } + self.assertEqual(14, prims_minimum_spanning(graph1)) + + graph2 = { + 1 : [ [7, 2], [6, 4] ], + 2 : [ [7, 1], [9, 4], [6, 3] ], + 3 : [ [8, 4], [6, 2] ], + 4 : [ [6, 1], [9, 2], [8, 3] ] + } + self.assertEqual(19, prims_minimum_spanning(graph2)) From 2f8be626a187724076ab7b603dd33d6f3f7273b9 Mon Sep 17 00:00:00 2001 From: Himanshu Airan <62210670+Himanshu-77@users.noreply.github.com> Date: Thu, 14 May 2020 15:43:45 +0530 Subject: [PATCH 214/302] Update prims_minimum_spanning.py function name changed --- algorithms/graph/prims_minimum_spanning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/graph/prims_minimum_spanning.py b/algorithms/graph/prims_minimum_spanning.py index 7e290d81a..02295c4c2 100644 --- a/algorithms/graph/prims_minimum_spanning.py +++ b/algorithms/graph/prims_minimum_spanning.py @@ -18,7 +18,7 @@ import heapq # for priority queue # prim's algo. to find weight of minimum spanning tree -def prims(graph_used): +def prims_minimum_spanning(graph_used): vis=[] s=[[0,1]] prim = [] From 3e7bd31d8b5106addf7e638aca8b0147a6a1c7b2 Mon Sep 17 00:00:00 2001 From: Himanshu Airan <62210670+Himanshu-77@users.noreply.github.com> Date: Fri, 15 May 2020 00:39:12 +0530 Subject: [PATCH 215/302] Update README.md link added for new file prims_minimum_spanning.py --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 06fb2d4c4..1fed65ab4 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ If you want to uninstall algorithms, it is as simple as: - [markov_chain](algorithms/graph/markov_chain.py) - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - [satisfiability](algorithms/graph/satisfiability.py) + - [minimum_spanning_tree_prims](algorithms/graph/prims_minimum_spanning.py) - [tarjan](algorithms/graph/tarjan.py) - [traversal](algorithms/graph/traversal.py) - [maximum_flow](algorithms/graph/maximum_flow.py) From 3e1a96516a2b5e7368684bb4eb3a31ac7aab6e93 Mon Sep 17 00:00:00 2001 From: NLe1 Date: Sun, 17 May 2020 17:57:07 -0700 Subject: [PATCH 216/302] fix import prism_minimum_spanning import --- algorithms/graph/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index 6675e6362..3bf3a1c8c 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -5,3 +5,4 @@ from .maximum_flow_dfs import * from .all_pairs_shortest_path import * from .bellman_ford import * +from .prims_minimum_spanning import * From db43efdb2e809043f81d6758ce541ead91d06314 Mon Sep 17 00:00:00 2001 From: Swapnanil Dutta <47251193+swapnanildutta@users.noreply.github.com> Date: Wed, 3 Jun 2020 04:30:23 +0530 Subject: [PATCH 217/302] Added Fibonacci Description (#658) Added the basic description of Fibonacci Numbers and the main aim of the functions. --- algorithms/dp/fib.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/algorithms/dp/fib.py b/algorithms/dp/fib.py index 6762e90db..7a6fd7140 100644 --- a/algorithms/dp/fib.py +++ b/algorithms/dp/fib.py @@ -1,3 +1,17 @@ +''' +In mathematics, the Fibonacci numbers, commonly denoted Fn, form a sequence, called the Fibonacci sequence, +such that each number is the sum of the two preceding ones, starting from 0 and 1. +That is, + F0=0 , F1=1 +and + Fn= F(n-1) + F(n-2) +The Fibonacci numbers are the numbers in the following integer sequence. + 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……. + +In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation + +Here, given a number n, print n-th Fibonacci Number. +''' def fib_recursive(n): """[summary] Computes the n-th fibonacci number recursive. From e6f1dbe72e6ba1bf4b4e72053b12254f8988f97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BF=8A=E4=B9=89?= <32086937+Sean16SYSU@users.noreply.github.com> Date: Sun, 21 Jun 2020 12:55:03 +0800 Subject: [PATCH 218/302] Manacher's algorithms - in Python (#575) * add_integer_divide * add_integer_divide * add_integer_divide * add_integer_divide * README updated * Manacher's algorithm * Manacher's algorithm * add Manacher's algorithm * with more snack test case * more snack cases for testing files * change the name of function `longestPalindrome` to `longest_palindrome` * test changed because the name of function changed --- README.md | 7 +-- algorithms/strings/__init__.py | 2 +- .../strings/longest_palindromic_substring.py | 44 +++++++++++++++++++ tests/test_strings.py | 23 +++++++++- 4 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 algorithms/strings/longest_palindromic_substring.py diff --git a/README.md b/README.md index 1fed65ab4..79c1d0808 100644 --- a/README.md +++ b/README.md @@ -329,9 +329,10 @@ If you want to uninstall algorithms, it is as simple as: - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) - [rotate](algorithms/strings/rotate.py) - [first_unique_char](algorithms/strings/first_unique_char.py) - - [repeat_substring](algorithms/strings/repeat_substring.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) - - [knuth_morris_pratt](algorithms/strings/knuth_morris_pratt.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) + - [longest_palindromic_substring](algorithms/strings/longest_palindromic_substring.py) + - [knuth_morris_pratt](algorithms/strings/knuth_morris_pratt.py) - [tree](algorithms/tree) - [bst](algorithms/tree/bst) - [array_to_bst](algorithms/tree/bst/array_to_bst.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 3e6bc19d4..72ea7d70d 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -35,5 +35,5 @@ from .first_unique_char import * from .repeat_substring import * from .atbash_cipher import * +from .longest_palindromic_substring import * from .knuth_morris_pratt import * - diff --git a/algorithms/strings/longest_palindromic_substring.py b/algorithms/strings/longest_palindromic_substring.py new file mode 100644 index 000000000..ad0c831b9 --- /dev/null +++ b/algorithms/strings/longest_palindromic_substring.py @@ -0,0 +1,44 @@ +''' +Given string s, find the longest palindromic substring. + +Example1: + +* input: "dasdasdasdasdasdadsa" +* output: "asdadsa" + +Example2: + +* input: "acdbbdaa" +* output: "dbbd" + +Manacher's algorithm + +''' + +def longest_palindrome(s): + if len(s) < 2: + return s + + n_str = '#' + '#'.join(s) + '#' + p = [0] * len(n_str) + mx, loc = 0, 0 + index, maxlen = 0, 0 + for i in range(len(n_str)): + if i < mx and 2 * loc - i < len(n_str): + p[i] = min(mx - i, p[2 * loc - i]) + else: + p[i] = 1 + + while p[i] + i < len(n_str) and i - p[i] >= 0 and n_str[ + i - p[i]] == n_str[i + p[i]]: + p[i] += 1 + + if i + p[i] > mx: + mx = i + p[i] + loc = i + + if p[i] > maxlen: + index = i + maxlen = p[i] + s = n_str[index - p[index] + 1:index + p[index]] + return s.replace('#', '') diff --git a/tests/test_strings.py b/tests/test_strings.py index 48fafd2a5..b8750b1f8 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -38,6 +38,7 @@ first_unique_char, repeat_substring, atbash, + longest_palindrome, knuth_morris_pratt ) @@ -527,24 +528,44 @@ class TestAtbashCipher(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ - + def test_atbash_cipher(self): self.assertEqual("zyxwvutsrqponml", atbash("abcdefghijklmno")) self.assertEqual("KbgslM", atbash("PythoN")) self.assertEqual("AttaCK at DawN", atbash("ZggzXP zg WzdM")) self.assertEqual("ZggzXP zg WzdM", atbash("AttaCK at DawN")) + + + +class TestLongestPalindromicSubstring(unittest.TestCase): + """[summary] + Test for the file longest_palindromic_substring.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_longest_palindromic_substring(self): + self.assertEqual("bb", longest_palindrome("cbbd")) + self.assertEqual("abba", longest_palindrome("abba")) + self.assertEqual("asdadsa", longest_palindrome("dasdasdasdasdasdadsa")) + self.assertEqual("abba", longest_palindrome("cabba")) + class TestKnuthMorrisPratt(unittest.TestCase): """[summary] Test for the file knuth_morris_pratt.py + Arguments: unittest {[type]} -- [description] """ + def test_knuth_morris_pratt(self): self.assertEqual([0, 1, 2, 3, 4], knuth_morris_pratt("aaaaaaa", "aaa")) self.assertEqual([0, 4], knuth_morris_pratt("abcdabc", "abc")) self.assertEqual([], knuth_morris_pratt("aabcdaab", "aba")) + if __name__ == "__main__": unittest.main() From ab5f01db209895abd424907514077fb087cc8d4a Mon Sep 17 00:00:00 2001 From: blucruz Date: Sun, 21 Jun 2020 22:22:56 +0800 Subject: [PATCH 219/302] Update flatten.py (#647) --- algorithms/arrays/flatten.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algorithms/arrays/flatten.py b/algorithms/arrays/flatten.py index f19156a09..52f4ec56d 100644 --- a/algorithms/arrays/flatten.py +++ b/algorithms/arrays/flatten.py @@ -11,7 +11,7 @@ def flatten(input_arr, output_arr=None): if output_arr is None: output_arr = [] for ele in input_arr: - if isinstance(ele, Iterable): + if not isinstance(ele, str) and isinstance(ele, Iterable): flatten(ele, output_arr) #tail-recursion else: output_arr.append(ele) #produce the result @@ -25,7 +25,7 @@ def flatten_iter(iterable): returns generator which produces one dimensional output. """ for element in iterable: - if isinstance(element, Iterable): + if not isinstance(element, str) and isinstance(element, Iterable): yield from flatten_iter(element) else: yield element From 20c1c4ec8de2a36a0640ad071e003f843c5c6c75 Mon Sep 17 00:00:00 2001 From: Rakshit Parashar <34675136+rishu2403@users.noreply.github.com> Date: Sun, 21 Jun 2020 19:53:32 +0530 Subject: [PATCH 220/302] Update binary_search.py (#657) --- algorithms/search/binary_search.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/algorithms/search/binary_search.py b/algorithms/search/binary_search.py index 644f98f8e..d8bccf06b 100644 --- a/algorithms/search/binary_search.py +++ b/algorithms/search/binary_search.py @@ -1,9 +1,13 @@ # # Binary search works for a sorted array. # Note: The code logic is written for an array sorted in -# increasing order. -# T(n): O(log n) -# +# increasing order. +#For Binary Search, T(N) = T(N/2) + O(1) // the recurrence relation +#Apply Masters Theorem for computing Run time complexity of recurrence relations : T(N) = aT(N/b) + f(N) +#Here, a = 1, b = 2 => log (a base b) = 1 +# also, here f(N) = n^c log^k(n) //k = 0 & c = log (a base b) So, T(N) = O(N^c log^(k+1)N) = O(log(N)) + + def binary_search(array, query): lo, hi = 0, len(array) - 1 while lo <= hi: From 82500bad28b9773e62ef8d6d629d574d5c0156ff Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 29 Jun 2020 17:02:14 -0400 Subject: [PATCH 221/302] add pigeonhole sort --- README.md | 1 + algorithms/sort/pigeonhole_sort.py | 28 ++++++++++++++++++++++++++++ tests/test_sort.py | 5 +++++ 3 files changed, 34 insertions(+) create mode 100644 algorithms/sort/pigeonhole_sort.py diff --git a/README.md b/README.md index 79c1d0808..82bb81a69 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,7 @@ If you want to uninstall algorithms, it is as simple as: - [meeting_rooms](algorithms/sort/meeting_rooms.py) - [merge_sort](algorithms/sort/merge_sort.py) - [pancake_sort](algorithms/sort/pancake_sort.py) + - [pigeonhole_sort](algorithms/sort/pigeonhole_sort.py) - [quick_sort](algorithms/sort/quick_sort.py) - [radix_sort](algorithms/sort/radix_sort.py) - [selection_sort](algorithms/sort/selection_sort.py) diff --git a/algorithms/sort/pigeonhole_sort.py b/algorithms/sort/pigeonhole_sort.py new file mode 100644 index 000000000..0569aa994 --- /dev/null +++ b/algorithms/sort/pigeonhole_sort.py @@ -0,0 +1,28 @@ +""" + +https://en.wikipedia.org/wiki/Pigeonhole_sort + +Time complexity: O(n + Range) where n = number of elements and Range = possible values in the array + +Suitable for lists where the number of elements and key values are mostly the same. + +""" + + +def pigeonhole_sort(arr): + Max = max(arr) + Min = min(arr) + size = Max - Min + 1 + + holes = [0]*size + + for i in arr: + holes[i-Min] += 1 + + i = 0 + for count in range(size): + while holes[count] > 0: + holes[count] -= 1 + arr[i] = count + Min + i += 1 + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index 650f33920..e2da29132 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -9,6 +9,7 @@ insertion_sort, merge_sort, pancake_sort, + pigeonhole_sort, quick_sort, selection_sort, bucket_sort, @@ -70,6 +71,10 @@ def test_merge_sort(self): def test_pancake_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], pancake_sort([1, 5, 65, 23, 57, 1232])) + + def test_pigeonhole_sort(self): + self.assertEqual([1, 5, 23, 57, 65, 1232], + pigeonhole_sort([1, 5, 65, 23, 57, 1232])) def test_quick_sort(self): self.assertEqual([1, 5, 23, 57, 65, 1232], From 90fafee4bae4ec3156852d741a8e9f7f22040d15 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 29 Jun 2020 17:48:41 -0400 Subject: [PATCH 222/302] export function pigeonhole_sort --- algorithms/sort/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index fceb3bd22..ee78300c6 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -8,6 +8,7 @@ from .insertion_sort import * from .merge_sort import * from .pancake_sort import * +from .pigeonhole_sort import * from .quick_sort import * from .selection_sort import * from .top_sort import * From e5ffcb4ecd85c2f08dc53e107713390d2b61e1ee Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 1 Jul 2020 02:56:15 -0400 Subject: [PATCH 223/302] add check pangram --- README.md | 1 + algorithms/strings/__init__.py | 1 + algorithms/strings/check_pangram.py | 10 ++++++++++ tests/test_strings.py | 6 ++++++ 4 files changed, 18 insertions(+) create mode 100644 algorithms/strings/check_pangram.py diff --git a/README.md b/README.md index 79c1d0808..f2adbaadf 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,7 @@ If you want to uninstall algorithms, it is as simple as: - [judge_circle](algorithms/strings/judge_circle.py) - [strong_password](algorithms/strings/strong_password.py) - [caesar_cipher](algorithms/strings/caesar_cipher.py) + - [check_pangram](algorithms/strings/check_pangram.py - [contain_string](algorithms/strings/contain_string.py) - [count_binary_substring](algorithms/strings/count_binary_substring.py) - [repeat_string](algorithms/strings/repeat_string.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 72ea7d70d..37c83dfdd 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -25,6 +25,7 @@ from .judge_circle import * from .strong_password import * from .caesar_cipher import * +from .check_pangram import * from .contain_string import * from .count_binary_substring import * from .repeat_string import * diff --git a/algorithms/strings/check_pangram.py b/algorithms/strings/check_pangram.py new file mode 100644 index 000000000..412425793 --- /dev/null +++ b/algorithms/strings/check_pangram.py @@ -0,0 +1,10 @@ +""" +Algorithm that checks if a given string is a pangram or not +""" + +def check_pangram(input_string): + alphabet = "abcdefghijklmnopqrstuvwxyz" + for ch in alphabet: + if ch not in input_string.lower(): + return False + return True \ No newline at end of file diff --git a/tests/test_strings.py b/tests/test_strings.py index b8750b1f8..5544086fa 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -28,6 +28,7 @@ judge_circle, strong_password, caesar_cipher, + check_pangram, contain_string, count_binary_substring, repeat_string, @@ -454,6 +455,11 @@ def test_caesar_cipher(self): self.assertEqual("Lipps_Asvph!", caesar_cipher("Hello_World!", 4)) self.assertEqual("okffng-Qwvb", caesar_cipher("middle-Outz", 2)) +class TestCheckPangram(unittest.TestCase): + def test_check_pangram(self): + self.assertTrue(check_pangram("The quick brown fox jumps over the lazy dog")) + self.assertFalse(check_pangram("The quick brown fox")) + class TestContainString(unittest.TestCase): def test_contain_string(self): From 81a19a775829fdb2d8c968fc1d2b09e3d0eb6d1f Mon Sep 17 00:00:00 2001 From: Reinhold <63191266+reinhold-b@users.noreply.github.com> Date: Fri, 14 Aug 2020 17:20:08 +0200 Subject: [PATCH 224/302] Adding the interpolation search algorithm (#686) * adding interpolation search * requested changes, tests, readme * add to __init__.py * add interpolation_search * add interpolation_search to README * add interpolation_search to README --- README.md | 1 + algorithms/search/__init__.py | 1 + algorithms/search/interpolation_search.py | 53 +++++++++++++++++++++++ tests/test_search.py | 16 ++++++- 4 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 algorithms/search/interpolation_search.py diff --git a/README.md b/README.md index 79c1d0808..c1b369271 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,7 @@ If you want to uninstall algorithms, it is as simple as: - [search_rotate](algorithms/search/search_rotate.py) - [jump_search](algorithms/search/jump_search.py) - [next_greatest_letter](algorithms/search/next_greatest_letter.py) + - [interpolation_search](algorithms/search/interpolation_search.py) - [set](algorithms/set) - [randomized_set](algorithms/set/randomized_set.py) - [set_covering](algorithms/set/set_covering.py) diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index ac5220b38..2586605e1 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -9,3 +9,4 @@ from .search_rotate import * from .jump_search import * from .next_greatest_letter import * +from .interpolation_search import * diff --git a/algorithms/search/interpolation_search.py b/algorithms/search/interpolation_search.py new file mode 100644 index 000000000..0759180e3 --- /dev/null +++ b/algorithms/search/interpolation_search.py @@ -0,0 +1,53 @@ +""" +Python implementation of the Interpolation Search algorithm. +Given a sorted array in increasing order, interpolation search calculates +the starting point of its search according to the search key. + +FORMULA: start_pos = low + [ (x - arr[low])*(high - low) / (arr[high] - arr[low]) ] + +Doc: https://en.wikipedia.org/wiki/Interpolation_search + +Time Complexity: O(log2(log2 n)) for average cases, O(n) for the worst case. +The algorithm performs best with uniformly distributed arrays. +""" + +from typing import List + + +def interpolation_search(array: List[int], search_key: int) -> int: + """ + :param array: The array to be searched. + :param search_key: The key to be searched in the array. + + :returns: Index of search_key in array if found, else -1. + + Example + + >>> interpolation_search([1, 10, 12, 15, 20, 41, 55], 20) + 4 + >>> interpolation_search([5, 10, 12, 14, 17, 20, 21], 55) + -1 + + """ + + # highest and lowest index in array + high = len(array) - 1 + low = 0 + + while low <= high and search_key in range(low, array[high] + 1): + # calculate the search position + pos = low + int(((search_key - array[low]) * + (high - low) / (array[high] - array[low]))) + + # if array[pos] equals the search_key then return pos as the index + if search_key == array[pos]: + return pos + # if the search_key is greater than array[pos] restart the search with the + # subarray greater than array[pos] + elif search_key > array[pos]: + low = pos + 1 + # in this case start the search with the subarray smaller than current array[pos] + elif search_key < array[pos]: + high = pos - 1 + + return -1 diff --git a/tests/test_search.py b/tests/test_search.py index 60d8919f7..3f6c23f3e 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -9,11 +9,13 @@ find_min_rotate, find_min_rotate_recur, search_rotate, search_rotate_recur, jump_search, - next_greatest_letter, next_greatest_letter_v1, next_greatest_letter_v2 + next_greatest_letter, next_greatest_letter_v1, next_greatest_letter_v2, + interpolation_search ) import unittest + class TestSuite(unittest.TestCase): def test_first_occurrence(self): @@ -56,7 +58,7 @@ def test_linear_search(self): self.assertEqual(-1, linear_search(array, -1)) def test_search_insert(self): - array = [1,3,5,6] + array = [1, 3, 5, 6] self.assertEqual(2, search_insert(array, 5)) self.assertEqual(1, search_insert(array, 2)) self.assertEqual(4, search_insert(array, 7)) @@ -122,6 +124,16 @@ def test_next_greatest_letter(self): self.assertEqual("c", next_greatest_letter_v1(letters, target)) self.assertEqual("c", next_greatest_letter_v2(letters, target)) + def test_interpolation_search(self): + array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20] + self.assertEqual(1, interpolation_search(array, 3)) + self.assertEqual(2, interpolation_search(array, 5)) + self.assertEqual(6, interpolation_search(array, 12)) + self.assertEqual(-1, interpolation_search(array, 22)) + self.assertEqual(-1, interpolation_search(array, -10)) + self.assertEqual(10, interpolation_search(array, 20)) + + if __name__ == '__main__': unittest.main() From b928e1fc93c14f9fa656d5908f724d02c8c2e54a Mon Sep 17 00:00:00 2001 From: Iheb Haboubi Date: Fri, 14 Aug 2020 19:34:57 +0100 Subject: [PATCH 225/302] Add binary exponentiation (#687) * Add binary exponentiation * Export power functions * Fix bug in power_recur function * Add tests for power functions in power.py * Fix typo in test * Add power.py link to README.md --- README.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/power.py | 45 ++++++++++++++++++++++++++++++++++++ tests/test_maths.py | 22 ++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 algorithms/maths/power.py diff --git a/README.md b/README.md index c1b369271..f06cbf1ab 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,7 @@ If you want to uninstall algorithms, it is as simple as: - [is_isomorphic](algorithms/map/is_isomorphic.py) - [is_anagram](algorithms/map/is_anagram.py) - [maths](algorithms/maths) + - [power](algorithms/maths/power.py) - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [cosine_similarity](algorithms/maths/cosine_similarity.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 7b8a7b1ec..678d923df 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -18,3 +18,4 @@ from .find_order_simple import * from .find_primitive_root_simple import * from .diffie_hellman_key_exchange import * +from .power import * diff --git a/algorithms/maths/power.py b/algorithms/maths/power.py new file mode 100644 index 000000000..99e694faf --- /dev/null +++ b/algorithms/maths/power.py @@ -0,0 +1,45 @@ +def power(a: int, n: int, r: int = None): + """ + Iterative version of binary exponentiation + + Calculate a ^ n + if r is specified, return the result modulo r + + Time Complexity : O(log(n)) + Space Complexity : O(1) + """ + ans = 1 + while n: + if n & 1: + ans = ans * a + a = a * a + if r: + ans %= r + a %= r + n >>= 1 + return ans + + +def power_recur(a: int, n: int, r: int = None): + """ + Recursive version of binary exponentiation + + Calculate a ^ n + if r is specified, return the result modulo r + + Time Complexity : O(log(n)) + Space Complexity : O(log(n)) + """ + if n == 0: + ans = 1 + elif n == 1: + ans = a + else: + ans = power_recur(a, n // 2, r) + ans = ans * ans + if n % 2: + ans = ans * a + if r: + ans %= r + return ans + diff --git a/tests/test_maths.py b/tests/test_maths.py index c29a8664a..a79c69084 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,4 +1,5 @@ from algorithms.maths import ( + power,power_recur, int_to_base, base_to_int, decimal_to_binary_ip, euler_totient, @@ -25,6 +26,27 @@ import unittest +class TestPower(unittest.TestCase): + """ + Test for the file power.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_power(self): + self.assertEqual(8, power(2, 3)) + self.assertEqual(1, power(5, 0)) + self.assertEqual(0, power(10, 3, 5)) + self.assertEqual(280380, power(2265, 1664,465465)) + + def test_power_recur(self): + self.assertEqual(8, power_recur(2, 3)) + self.assertEqual(1, power_recur(5, 0)) + self.assertEqual(0, power_recur(10, 3, 5)) + self.assertEqual(280380, power_recur(2265, 1664,465465)) + + class TestBaseConversion(unittest.TestCase): """ Test for the file base_conversion.py From 07278be93ceb7735493ac35475491686176a9c7b Mon Sep 17 00:00:00 2001 From: chiralevy <51869089+chiralevy@users.noreply.github.com> Date: Sun, 16 Aug 2020 18:04:32 -0400 Subject: [PATCH 226/302] Optimized string is_palindrome main function (#688) Co-authored-by: loan --- algorithms/strings/is_palindrome.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algorithms/strings/is_palindrome.py b/algorithms/strings/is_palindrome.py index 0318bf5f4..40f404a37 100644 --- a/algorithms/strings/is_palindrome.py +++ b/algorithms/strings/is_palindrome.py @@ -21,9 +21,9 @@ def is_palindrome(s): i = 0 j = len(s)-1 while i < j: - while i < j and not s[i].isalnum(): + while not s[i].isalnum(): i += 1 - while i < j and not s[j].isalnum(): + while not s[j].isalnum(): j -= 1 if s[i].lower() != s[j].lower(): return False From 4b5ccf29e415eff67cf3b947df03da8dfc5bdd49 Mon Sep 17 00:00:00 2001 From: Herpacsi Benedek Date: Sun, 27 Sep 2020 18:19:52 +0200 Subject: [PATCH 227/302] Fixed readme's dfa.py link (#695) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f06cbf1ab..e38640143 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ If you want to uninstall algorithms, it is as simple as: - [move_zeros](algorithms/arrays/move_zeros.py) - [n_sum](algorithms/arrays/n_sum.py) - [automata](algorithms/automata) - - [DFA](algorithms/automata/DFA.py) + - [DFA](algorithms/automata/dfa.py) - [backtrack](algorithms/backtrack) - [general_solution.md](algorithms/backtrack/) - [add_operators](algorithms/backtrack/add_operators.py) @@ -196,7 +196,7 @@ If you want to uninstall algorithms, it is as simple as: - [valid_sudoku](algorithms/map/valid_sudoku.py) - [word_pattern](algorithms/map/word_pattern.py) - [is_isomorphic](algorithms/map/is_isomorphic.py) - - [is_anagram](algorithms/map/is_anagram.py) + - [is_anagram](algorithms/map/is_anagram.py) - [maths](algorithms/maths) - [power](algorithms/maths/power.py) - [base_conversion](algorithms/maths/base_conversion.py) @@ -205,7 +205,7 @@ If you want to uninstall algorithms, it is as simple as: - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - [euler_totient](algorithms/maths/euler_totient.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) + - [factorial](algorithms/maths/factorial.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) From a68ec8aa789b3e5f27bcc2978eb0166ab455218d Mon Sep 17 00:00:00 2001 From: Arijit Gupta Date: Wed, 30 Sep 2020 23:51:19 +0530 Subject: [PATCH 228/302] Adding stooge sort (#697) * Create stooge_sort.py * Update stooge_sort.py * Update README.md * Update __init__.py * Update test_sort.py * Update stooge_sort.py * Update test_sort.py * Update stooge_sort.py --- README.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/stooge_sort.py | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 algorithms/sort/stooge_sort.py diff --git a/README.md b/README.md index e38640143..54f6c6a44 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,7 @@ If you want to uninstall algorithms, it is as simple as: - [selection_sort](algorithms/sort/selection_sort.py) - [shell_sort](algorithms/sort/shell_sort.py) - [sort_colors](algorithms/sort/sort_colors.py) + - [stooge_sort](algorithms/sort/stooge_sort.py) - [top_sort](algorithms/sort/top_sort.py) - [wiggle_sort](algorithms/sort/wiggle_sort.py) - [stack](algorithms/stack) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index fceb3bd22..5a870feff 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -13,6 +13,7 @@ from .top_sort import * from .bucket_sort import * from .shell_sort import * +from .stooge_sort import * from .radix_sort import * from .gnome_sort import * from .cocktail_shaker_sort import * diff --git a/algorithms/sort/stooge_sort.py b/algorithms/sort/stooge_sort.py new file mode 100644 index 000000000..42f8b3bd4 --- /dev/null +++ b/algorithms/sort/stooge_sort.py @@ -0,0 +1,43 @@ +''' + +Stooge Sort +Time Complexity : O(n2.709) +Reference: https://www.geeksforgeeks.org/stooge-sort/ + +''' + + + +def stoogesort(arr, l, h): + if l >= h: + return + + # If first element is smaller + # than last, swap them + if arr[l]>arr[h]: + t = arr[l] + arr[l] = arr[h] + arr[h] = t + + # If there are more than 2 elements in + # the array + if h-l + 1 > 2: + t = (int)((h-l + 1)/3) + + # Recursively sort first 2 / 3 elements + stoogesort(arr, l, (h-t)) + + # Recursively sort last 2 / 3 elements + stoogesort(arr, l + t, (h)) + + # Recursively sort first 2 / 3 elements + # again to confirm + stoogesort(arr, l, (h-t)) + + +if __name__ == "__main__": + array = [1,3,64,5,7,8] + n = len(array) + stoogesort(array, 0, n-1) + for i in range(0, n): + print(array[i], end = ' ') From 38a86ec7e01c90af667a359062203acda9c67896 Mon Sep 17 00:00:00 2001 From: jonathan hanley Date: Thu, 1 Oct 2020 22:00:20 +0100 Subject: [PATCH 229/302] Updated sorting tests to make tests more readable. Added helper function to allow for easier testing of future algorithms --- tests/test_sort.py | 75 ++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/tests/test_sort.py b/tests/test_sort.py index 650f33920..c24e20da8 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -22,82 +22,73 @@ import unittest +def is_sorted(array): + """ + Helper function to check if the given array is sorted. + :param array: Array to check if sorted + :return: True if sorted in ascending order, else False + """ + for i in range(len(array) - 1): + if array[i] > array[i + 1]: + return False + + return True + + class TestSuite(unittest.TestCase): def test_bogo_sort(self): - self.assertEqual([1, 5, 23], - bogo_sort([1, 23, 5])) + self.assertTrue(is_sorted(bogo_sort([1, 23, 5]))) def test_bitonic_sort(self): - self.assertEqual([1, 2, 3, 5, 23, 57, 65, 1232], - bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232])) - self.assertEqual([1, 2, 3, 5, 23, 57, 65, 1232], - bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232],False)) - self.assertEqual([1232, 65, 57, 23, 5, 3, 2, 1], - bitonic_sort([1, 2, 3, 5, 65, 23, 57, 1232],True)) + self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_bubble_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - bubble_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(bubble_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_comb_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - comb_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(comb_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_counting_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - counting_sort([1, 5, 65, 23, 57, 1232])) - self.assertEqual([-1232, -65, -57, -23, -5, -1], - counting_sort([-1, -5, -65, -23, -57, -1232])) + self.assertTrue(is_sorted(counting_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_cycle_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - cycle_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(cycle_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_heap_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - max_heap_sort([1, 5, 65, 23, 57, 1232])) - self.assertEqual([1, 5, 23, 57, 65, 1232], - min_heap_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(max_heap_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + + self.assertTrue(is_sorted(min_heap_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_insertion_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - insertion_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_merge_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - merge_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(merge_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_pancake_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - pancake_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(pancake_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_quick_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - quick_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(quick_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_selection_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - selection_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(selection_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_bucket_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - bucket_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(bucket_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_shell_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - shell_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(shell_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_radix_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - radix_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(radix_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_gnome_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - gnome_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(gnome_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_cocktail_shaker_sort(self): - self.assertEqual([1, 5, 23, 57, 65, 1232], - cocktail_shaker_sort([1, 5, 65, 23, 57, 1232])) + self.assertTrue(is_sorted(cocktail_shaker_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + class TestTopSort(unittest.TestCase): def setUp(self): From c5d3e2d2766865ed14269c868bf1ad9f6a8a5c4a Mon Sep 17 00:00:00 2001 From: utkarsh Date: Fri, 2 Oct 2020 17:52:23 +0530 Subject: [PATCH 230/302] Added matrix_exponentiation in algorithms/matrix --- README.md | 1 + algorithms/matrix/__init__.py | 2 +- algorithms/matrix/matrix_exponentiation.py | 60 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 algorithms/matrix/matrix_exponentiation.py diff --git a/README.md b/README.md index 54f6c6a44..4620da2a7 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,7 @@ If you want to uninstall algorithms, it is as simple as: - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [matrix_exponentiation](algorithms/matrix/matrix_exponentiation.py) - [modular_exponential](algorithms/maths/modular_exponential.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) diff --git a/algorithms/matrix/__init__.py b/algorithms/matrix/__init__.py index 8b1378917..30fc44463 100644 --- a/algorithms/matrix/__init__.py +++ b/algorithms/matrix/__init__.py @@ -1 +1 @@ - +from .matrix_exponentiation import * diff --git a/algorithms/matrix/matrix_exponentiation.py b/algorithms/matrix/matrix_exponentiation.py new file mode 100644 index 000000000..a08c365b3 --- /dev/null +++ b/algorithms/matrix/matrix_exponentiation.py @@ -0,0 +1,60 @@ +def multiply(matA: list, matB: list) -> list: + """ + Multiplies two square matrices matA and matB od size n x n + Time Complexity: O(n^3) + """ + n = len(matA) + matC = [[0 for i in range(n)] for j in range(n)] + + for i in range(n): + for j in range(n): + for k in range(n): + matC[i][j] += matA[i][k] * matB[k][j] + + return matC + +def identity(n: int) -> list: + """ + Returns the Identity matrix of size n x n + Time Complecity: O(n^2) + """ + I = [[0 for i in range(n)] for j in range(n)] + + for i in range(n): + I[i][i] = 1 + + return I + +def matrix_exponentiation(mat: list, n: int) -> list: + """ + Calculates mat^n by repeated squaring + Time Complexity: O(d^3 log(n)) + d: dimesion of the square matrix mat + n: power the matrix is raised to + """ + if n == 0: + return identity(len(mat)) + elif n % 2 == 1: + return multiply(matrix_exponentiation(mat, n - 1), mat) + else: + tmp = matrix_exponentiation(mat, n // 2) + return multiply(tmp, tmp) + +if __name__ == "__main__": + mat = [[1, 0, 2], [2, 1, 0], [0, 2, 1]] + + res0 = matrix_exponentiation(mat, 0) + assert res0 == [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + print(f"{mat}^0 = {res0}") + + res1 = matrix_exponentiation(mat, 1) + assert res1 == [[1, 0, 2], [2, 1, 0], [0, 2, 1]] + print(f"{mat}^1 = {res1}") + + res2 = matrix_exponentiation(mat, 2) + assert res2 == [[1, 4, 4], [4, 1, 4], [4, 4, 1]] + print(f"{mat}^2 = {res2}") + + res5 = matrix_exponentiation(mat, 5) + assert res5 == [[81, 72, 90], [90, 81, 72], [72, 90, 81]] + print(f"{mat}^5 = {res5}") \ No newline at end of file From 0e61ad8dfdbdeb0fd8e8fb129e919cea7afd0b2a Mon Sep 17 00:00:00 2001 From: utkarsh Date: Fri, 2 Oct 2020 17:55:20 +0530 Subject: [PATCH 231/302] Added matrix_exponentiation under matrix in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4620da2a7..618c4fd50 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,6 @@ If you want to uninstall algorithms, it is as simple as: - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [matrix_exponentiation](algorithms/matrix/matrix_exponentiation.py) - [modular_exponential](algorithms/maths/modular_exponential.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) @@ -231,6 +230,7 @@ If you want to uninstall algorithms, it is as simple as: - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - [copy_transform](algorithms/matrix/copy_transform.py) - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_exponentiation](algorithms/matrix/matrix_exponentiation.py) - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - [matrix_inversion](algorithms/matrix/matrix_inversion.py) - [matrix_multiplication](algorithms/matrix/multiply.py) From d1e19564377e09bd275aac2505e124f728c055e9 Mon Sep 17 00:00:00 2001 From: utkarsh Date: Fri, 2 Oct 2020 19:41:53 +0530 Subject: [PATCH 232/302] Added tests to tests/test_matrix and modified __init__.py --- algorithms/matrix/__init__.py | 1 - algorithms/matrix/matrix_exponentiation.py | 19 ----------------- tests/test_matrix.py | 24 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/algorithms/matrix/__init__.py b/algorithms/matrix/__init__.py index 30fc44463..e69de29bb 100644 --- a/algorithms/matrix/__init__.py +++ b/algorithms/matrix/__init__.py @@ -1 +0,0 @@ -from .matrix_exponentiation import * diff --git a/algorithms/matrix/matrix_exponentiation.py b/algorithms/matrix/matrix_exponentiation.py index a08c365b3..f842bc2fd 100644 --- a/algorithms/matrix/matrix_exponentiation.py +++ b/algorithms/matrix/matrix_exponentiation.py @@ -39,22 +39,3 @@ def matrix_exponentiation(mat: list, n: int) -> list: else: tmp = matrix_exponentiation(mat, n // 2) return multiply(tmp, tmp) - -if __name__ == "__main__": - mat = [[1, 0, 2], [2, 1, 0], [0, 2, 1]] - - res0 = matrix_exponentiation(mat, 0) - assert res0 == [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - print(f"{mat}^0 = {res0}") - - res1 = matrix_exponentiation(mat, 1) - assert res1 == [[1, 0, 2], [2, 1, 0], [0, 2, 1]] - print(f"{mat}^1 = {res1}") - - res2 = matrix_exponentiation(mat, 2) - assert res2 == [[1, 4, 4], [4, 1, 4], [4, 4, 1]] - print(f"{mat}^2 = {res2}") - - res5 = matrix_exponentiation(mat, 5) - assert res5 == [[81, 72, 90], [90, 81, 72], [72, 90, 81]] - print(f"{mat}^5 = {res5}") \ No newline at end of file diff --git a/tests/test_matrix.py b/tests/test_matrix.py index da041e027..88a9b6f73 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -3,6 +3,7 @@ copy_transform, crout_matrix_decomposition, cholesky_matrix_decomposition, + matrix_exponentiation, matrix_inversion, multiply, rotate_image, @@ -159,6 +160,29 @@ def test_inversion(self): [Fraction(13, 53), Fraction(-22, 53), Fraction(5, 53)]]) +class TestMatrixExponentiation(unittest.TestCase): + """[summary] + Test for the file matrix_exponentiation.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_matrix_exponentiation(self): + mat = [[1, 0, 2], [2, 1, 0], [0, 2, 1]] + + self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 0), + [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 1), + [[1, 0, 2], [2, 1, 0], [0, 2, 1]]) + + self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 2), + [[1, 4, 4], [4, 1, 4], [4, 4, 1]]) + + self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 5), + [[81, 72, 90], [90, 81, 72], [72, 90, 81]]) + class TestMultiply(unittest.TestCase): """[summary] From 4ff61dda51a2b02e49699d97aee570b97d5c913e Mon Sep 17 00:00:00 2001 From: HARDIK DADHICH Date: Fri, 2 Oct 2020 20:43:33 +0530 Subject: [PATCH 233/302] fixing link for connected component in readme (#714) Co-authored-by: Hardik dadhich --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb6c4c09c..b530869c2 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ If you want to uninstall algorithms, it is as simple as: - [maximum_flow_dfs](algorithms/graph/maximum_flow_dfs.py) - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) - [bellman_ford](algorithms/graph/bellman_ford.py) - - [Count Connected Components](algoritms/graph/count_connected_number_of_component.py) + - [Count Connected Components](algorithms/graph/count_connected_number_of_component.py) - [heap](algorithms/heap) - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - [skyline](algorithms/heap/skyline.py) From 476fb94886a109a030a844e8fceead479f73470a Mon Sep 17 00:00:00 2001 From: Rahul Goswami Date: Sun, 4 Oct 2020 20:15:39 +0530 Subject: [PATCH 234/302] update and release v0.1.4 to PyPI --- README.md | 7 +++---- setup.py | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bc9acbae3..7aaafc137 100644 --- a/README.md +++ b/README.md @@ -223,15 +223,14 @@ If you want to uninstall algorithms, it is as simple as: - [hailstone](algorithms/maths/hailstone.py) - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) - [find_order](algorithms/maths/find_order_simple.py) - - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) + - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) + - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - [copy_transform](algorithms/matrix/copy_transform.py) - [count_paths](algorithms/matrix/count_paths.py) - [matrix_exponentiation](algorithms/matrix/matrix_exponentiation.py) - - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt) - [matrix_inversion](algorithms/matrix/matrix_inversion.py) - [matrix_multiplication](algorithms/matrix/multiply.py) - [rotate_image](algorithms/matrix/rotate_image.py) @@ -327,7 +326,7 @@ If you want to uninstall algorithms, it is as simple as: - [judge_circle](algorithms/strings/judge_circle.py) - [strong_password](algorithms/strings/strong_password.py) - [caesar_cipher](algorithms/strings/caesar_cipher.py) - - [check_pangram](algorithms/strings/check_pangram.py + - [check_pangram](algorithms/strings/check_pangram.py) - [contain_string](algorithms/strings/contain_string.py) - [count_binary_substring](algorithms/strings/count_binary_substring.py) - [repeat_string](algorithms/strings/repeat_string.py) diff --git a/setup.py b/setup.py index f08f24f14..56099a55c 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ def long_description(): setup(name='algorithms', - version='0.1.0', + version='0.1.4', description='Pythonic Data Structures and Algorithms', long_description=long_description(), long_description_content_type="text/markdown", @@ -19,11 +19,12 @@ def long_description(): author='Algorithms Team & Contributors', author_email="kwk236@gmail.com", license='MIT', - packages=find_packages(), + packages=find_packages(exclude=('tests', 'tests.*')), classifiers=[ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', ], zip_safe=False) From 7370b8d36af5dc26489f472f9dbe90dd16cc7a79 Mon Sep 17 00:00:00 2001 From: Beata Sudi Date: Fri, 9 Oct 2020 20:17:07 +0200 Subject: [PATCH 235/302] fixing delete_fixup() in red_black_tree (#722) --- algorithms/tree/red_black_tree/red_black_tree.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/algorithms/tree/red_black_tree/red_black_tree.py b/algorithms/tree/red_black_tree/red_black_tree.py index 6ced71ea6..4b3c0d66b 100644 --- a/algorithms/tree/red_black_tree/red_black_tree.py +++ b/algorithms/tree/red_black_tree/red_black_tree.py @@ -241,8 +241,7 @@ def delete_fixup(self, node): node.parent.color = 0 node_brother.right.color = 0 self.left_rotate(node.parent) - node = self.root - break + node = self.root else: node_brother = node.parent.left if node_brother.color == 1: @@ -264,8 +263,7 @@ def delete_fixup(self, node): node.parent.color = 0 node_brother.left.color = 0 self.right_rotate(node.parent) - node = self.root - break + node = self.root node.color = 0 def inorder(self): From bc0b1d33aad8e07bc6f35c54d1b5ace01ea92a9e Mon Sep 17 00:00:00 2001 From: Utkarsh Chaudhary Date: Mon, 12 Oct 2020 06:53:54 +0530 Subject: [PATCH 236/302] Added Modular Inverse (#721) --- README.md | 1 + algorithms/maths/modular_inverse.py | 34 +++++++++++++++++++++++++++++ tests/test_maths.py | 16 ++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 algorithms/maths/modular_inverse.py diff --git a/README.md b/README.md index 7aaafc137..a20a7407b 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ If you want to uninstall algorithms, it is as simple as: - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - [modular_exponential](algorithms/maths/modular_exponential.py) + - [modular_inverse](algorithms/maths/modular_inverse.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) diff --git a/algorithms/maths/modular_inverse.py b/algorithms/maths/modular_inverse.py new file mode 100644 index 000000000..f53d0f64f --- /dev/null +++ b/algorithms/maths/modular_inverse.py @@ -0,0 +1,34 @@ +# extended_gcd(a, b) modified from +# https://github.com/keon/algorithms/blob/master/algorithms/maths/extended_gcd.py + +def extended_gcd(a: int, b: int) -> [int, int, int]: + """Extended GCD algorithm. + Return s, t, g + such that a * s + b * t = GCD(a, b) + and s and t are co-prime. + """ + + old_s, s = 1, 0 + old_t, t = 0, 1 + old_r, r = a, b + + while r != 0: + quotient = old_r // r + + old_r, r = r, old_r - quotient * r + old_s, s = s, old_s - quotient * s + old_t, t = t, old_t - quotient * t + + return old_s, old_t, old_r + + +def modular_inverse(a: int, m: int) -> int: + """ + Returns x such that a * x = 1 (mod m) + a and m must be coprime + """ + + s, t, g = extended_gcd(a, m) + if g != 1: + raise ValueError("a and m must be coprime") + return s % m diff --git a/tests/test_maths.py b/tests/test_maths.py index a79c69084..766748878 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -8,6 +8,7 @@ gcd, lcm, trailing_zero, gcd_bit, gen_strobogrammatic, strobogrammatic_in_range, is_strobogrammatic, is_strobogrammatic2, + modular_inverse, modular_exponential, find_next_square, find_next_square2, prime_check, @@ -166,6 +167,21 @@ def test_is_strobogrammatic2(self): self.assertFalse(is_strobogrammatic2("14")) +class TestModularInverse(unittest.TestCase): + """[summary] + Test for the file modular_Exponential.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_modular_inverse(self): + # checks if x * x_inv == 1 (mod m) + self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 19) % 19) + self.assertEqual(1, 53 * modular_inverse.modular_inverse(53, 91) % 91) + self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 1000000007) % 1000000007) + self.assertRaises(ValueError, modular_inverse.modular_inverse, 2, 20) + class TestModularExponential(unittest.TestCase): """[summary] Test for the file modular_Exponential.py From 30512d9b181fb840dd3d7c39ecb182c257dcdf12 Mon Sep 17 00:00:00 2001 From: Nanak <36790357+Nanak360@users.noreply.github.com> Date: Fri, 23 Oct 2020 08:18:08 +0530 Subject: [PATCH 237/302] Add Krishnamurty Number to Math algorithms (#728) * add Krishnamurthy Number to Math algorithms * tests added for krishnamurthy number, readme update * Update function name of krishnamurthy_number.py Co-authored-by: Nanak Bandyopadhyay --- README.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/krishnamurthy_number.py | 43 ++++++++++++++++++++++++ tests/test_maths.py | 18 +++++++++- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 algorithms/maths/krishnamurthy_number.py diff --git a/README.md b/README.md index a20a7407b..3ba94d3ac 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,7 @@ If you want to uninstall algorithms, it is as simple as: - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [krishnamurthy_number](algorithms/maths/krishnamurthy_number.py) - [modular_exponential](algorithms/maths/modular_exponential.py) - [modular_inverse](algorithms/maths/modular_inverse.py) - [next_bigger](algorithms/maths/next_bigger.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 678d923df..b29b33b1d 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -19,3 +19,4 @@ from .find_primitive_root_simple import * from .diffie_hellman_key_exchange import * from .power import * +from .krishnamurthy_number import * \ No newline at end of file diff --git a/algorithms/maths/krishnamurthy_number.py b/algorithms/maths/krishnamurthy_number.py new file mode 100644 index 000000000..a0a451ee4 --- /dev/null +++ b/algorithms/maths/krishnamurthy_number.py @@ -0,0 +1,43 @@ +""" +A Krishnamurthy number is a number whose sum total of the factorials of each digit is equal to the number itself. + +Here's what I mean by that: + +"145" is a Krishnamurthy Number because, +1! + 4! + 5! = 1 + 24 + 120 = 145 + +"40585" is also a Krishnamurthy Number. +4! + 0! + 5! + 8! + 5! = 40585 + +"357" or "25965" is NOT a Krishnamurthy Number +3! + 5! + 7! = 6 + 120 + 5040 != 357 + +The following function will check if a number is a Krishnamurthy Number or not and return a boolean value. +""" + + +def find_factorial(n): + fact = 1 + while n != 0: + fact *= n + n -= 1 + return fact + + +def krishnamurthy_number(n): + if n == 0: + return False + sum_of_digits = 0 # will hold sum of FACTORIAL of digits + temp = n + + while temp != 0: + + # get the factorial of of the last digit of n and add it to sum_of_digits + sum_of_digits += find_factorial(temp % 10) + + # replace value of temp by temp/10 + # i.e. will remove the last digit from temp + temp //= 10 + + # returns True if number is krishnamurthy + return (sum_of_digits == n) diff --git a/tests/test_maths.py b/tests/test_maths.py index 766748878..f5586b63f 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -21,7 +21,8 @@ cosine_similarity, find_order, find_primitive_root, - alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange + alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, + krishnamurthy_number, ) import unittest @@ -393,6 +394,21 @@ def test_find_order_simple(self): self.assertEqual(-1, find_order(128, 256)) self.assertEqual(352, find_order(3, 353)) +class TestKrishnamurthyNumber(unittest.TestCase): + """[summary] + Test for the file krishnamurthy_number.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_krishnamurthy_number(self): + self.assertFalse(krishnamurthy_number(0)) + self.assertTrue(krishnamurthy_number(2)) + self.assertTrue(krishnamurthy_number(1)) + self.assertTrue(krishnamurthy_number(145)) + self.assertTrue(krishnamurthy_number(40585)) + class TestDiffieHellmanKeyExchange(unittest.TestCase): """[summary] From 422b1d16c1dd46a22ce971c6f2670603a22bdf97 Mon Sep 17 00:00:00 2001 From: Nanak <36790357+Nanak360@users.noreply.github.com> Date: Thu, 29 Oct 2020 23:44:57 +0530 Subject: [PATCH 238/302] Add Magic Number to maths algorithms (#730) * add magic number to maths * add Magic Number to maths * Update test_maths.py * Updated variable names and condition statements Co-authored-by: Nanak Bandyopadhyay --- README.md | 1 + algorithms/maths/__init__.py | 3 +- algorithms/maths/magic_number.py | 36 +++++++++++++++++++++++ tests/test_maths.py | 50 +++++++++++++++++++++++--------- 4 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 algorithms/maths/magic_number.py diff --git a/README.md b/README.md index 3ba94d3ac..bcd135f90 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,7 @@ If you want to uninstall algorithms, it is as simple as: - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [magic_number](algorithms/maths/magic_number.py) - [krishnamurthy_number](algorithms/maths/krishnamurthy_number.py) - [modular_exponential](algorithms/maths/modular_exponential.py) - [modular_inverse](algorithms/maths/modular_inverse.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index b29b33b1d..92902c66f 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -19,4 +19,5 @@ from .find_primitive_root_simple import * from .diffie_hellman_key_exchange import * from .power import * -from .krishnamurthy_number import * \ No newline at end of file +from .magic_number import * +from .krishnamurthy_number import * diff --git a/algorithms/maths/magic_number.py b/algorithms/maths/magic_number.py new file mode 100644 index 000000000..fe62bc680 --- /dev/null +++ b/algorithms/maths/magic_number.py @@ -0,0 +1,36 @@ +"""Magic Number +A number is said to be a magic number, +if the sum of its digits are calculated till a single digit recursively +by adding the sum of the digits after every addition. +If the single digit comes out to be 1,then the number is a magic number. + +Example: + Number = 50113 => 5+0+1+1+3=10 => 1+0=1 [This is a Magic Number] + Number = 1234 => 1+2+3+4=10 => 1+0=1 [This is a Magic Number] + Number = 199 => 1+9+9=19 => 1+9=10 => 1+0=1 [This is a Magic Number] + Number = 111 => 1+1+1=3 [This is NOT a Magic Number] + +The following function checks for Magic numbers and returns a Boolean accordingly. +""" + + +def magic_number(n): + total_sum = 0 + + # will end when n becomes 0 + # AND + # sum becomes single digit. + while n > 0 or total_sum > 9: + + # when n becomes 0 but we have a total_sum, + # we update the value of n with the value of the sum digits + if n == 0: + n = total_sum # only when sum of digits isn't single digit + total_sum = 0 + total_sum += n % 10 + n //= 10 + + # Return true if sum becomes 1 + return total_sum == 1 + + diff --git a/tests/test_maths.py b/tests/test_maths.py index f5586b63f..ecceb65e3 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,5 +1,5 @@ from algorithms.maths import ( - power,power_recur, + power, power_recur, int_to_base, base_to_int, decimal_to_binary_ip, euler_totient, @@ -19,10 +19,11 @@ combination, combination_memo, hailstone, cosine_similarity, + magic_number, find_order, find_primitive_root, - alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, - krishnamurthy_number, + alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, + diffie_hellman_key_exchange, krishnamurthy_number ) import unittest @@ -40,13 +41,13 @@ def test_power(self): self.assertEqual(8, power(2, 3)) self.assertEqual(1, power(5, 0)) self.assertEqual(0, power(10, 3, 5)) - self.assertEqual(280380, power(2265, 1664,465465)) + self.assertEqual(280380, power(2265, 1664, 465465)) def test_power_recur(self): self.assertEqual(8, power_recur(2, 3)) self.assertEqual(1, power_recur(5, 0)) self.assertEqual(0, power_recur(10, 3, 5)) - self.assertEqual(280380, power_recur(2265, 1664,465465)) + self.assertEqual(280380, power_recur(2265, 1664, 465465)) class TestBaseConversion(unittest.TestCase): @@ -136,6 +137,7 @@ def test_gcd_bit(self): self.assertEqual(4, gcd_bit(8, 12)) self.assertEqual(1, gcd(13, 17)) + class TestGenerateStroboGrammatic(unittest.TestCase): """[summary] Test for the file generate_strobogrammatic.py @@ -174,7 +176,7 @@ class TestModularInverse(unittest.TestCase): Arguments: unittest {[type]} -- [description] - """ + """ def test_modular_inverse(self): # checks if x * x_inv == 1 (mod m) @@ -183,6 +185,7 @@ def test_modular_inverse(self): self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 1000000007) % 1000000007) self.assertRaises(ValueError, modular_inverse.modular_inverse, 2, 20) + class TestModularExponential(unittest.TestCase): """[summary] Test for the file modular_Exponential.py @@ -193,8 +196,8 @@ class TestModularExponential(unittest.TestCase): def test_modular_exponential(self): self.assertEqual(1, modular_exponential(5, 117, 19)) - self.assertEqual(pow(1243, 65321, 10**9 + 7), - modular_exponential(1243, 65321, 10**9 + 7)) + self.assertEqual(pow(1243, 65321, 10 ** 9 + 7), + modular_exponential(1243, 65321, 10 ** 9 + 7)) self.assertEqual(1, modular_exponential(12, 0, 78)) self.assertRaises(ValueError, modular_exponential, 12, -2, 455) @@ -284,7 +287,6 @@ class TestRSA(unittest.TestCase): """ def test_encrypt_decrypt(self): - self.assertEqual(7, decrypt(encrypt(7, 23, 143), 47, 143)) # def test_key_generator(self): # this test takes a while! @@ -326,7 +328,7 @@ def test_factorial(self): self.assertEqual(1, factorial(0)) self.assertEqual(120, factorial(5)) self.assertEqual(3628800, factorial(10)) - self.assertEqual(637816310, factorial(34521, 10**9 + 7)) + self.assertEqual(637816310, factorial(34521, 10 ** 9 + 7)) self.assertRaises(ValueError, factorial, -42) self.assertRaises(ValueError, factorial, 42, -1) @@ -334,7 +336,7 @@ def test_factorial_recur(self): self.assertEqual(1, factorial_recur(0)) self.assertEqual(120, factorial_recur(5)) self.assertEqual(3628800, factorial_recur(10)) - self.assertEqual(637816310, factorial_recur(34521, 10**9 + 7)) + self.assertEqual(637816310, factorial_recur(34521, 10 ** 9 + 7)) self.assertRaises(ValueError, factorial_recur, -42) self.assertRaises(ValueError, factorial_recur, 42, -1) @@ -346,6 +348,7 @@ class TestHailstone(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_hailstone(self): self.assertEqual([8, 4, 2, 1], hailstone.hailstone(8)) self.assertEqual([10, 5, 16, 8, 4, 2, 1], hailstone.hailstone(10)) @@ -358,6 +361,7 @@ class TestCosineSimilarity(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_cosine_similarity(self): vec_a = [1, 1, 1] vec_b = [-1, -1, -1] @@ -374,12 +378,13 @@ class TestFindPrimitiveRoot(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_find_primitive_root_simple(self): self.assertListEqual([0], find_primitive_root(1)) self.assertListEqual([2, 3], find_primitive_root(5)) self.assertListEqual([], find_primitive_root(24)) self.assertListEqual([2, 5, 13, 15, 17, 18, 19, 20, 22, 24, 32, 35], find_primitive_root(37)) - + class TestFindOrder(unittest.TestCase): """[summary] @@ -388,6 +393,7 @@ class TestFindOrder(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_find_order_simple(self): self.assertEqual(1, find_order(1, 1)) self.assertEqual(6, find_order(3, 7)) @@ -410,6 +416,23 @@ def test_krishnamurthy_number(self): self.assertTrue(krishnamurthy_number(40585)) +class TestMagicNumber(unittest.TestCase): + """[summary] + Test for the file find_order_simple.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_magic_number(self): + self.assertTrue(magic_number(50113)) + self.assertTrue(magic_number(1234)) + self.assertTrue(magic_number(100)) + self.assertTrue(magic_number(199)) + self.assertFalse(magic_number(2000)) + self.assertFalse(magic_number(500000)) + + class TestDiffieHellmanKeyExchange(unittest.TestCase): """[summary] Test for the file diffie_hellman_key_exchange.py @@ -417,12 +440,13 @@ class TestDiffieHellmanKeyExchange(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_find_order_simple(self): self.assertFalse(diffie_hellman_key_exchange(3, 6)) self.assertTrue(diffie_hellman_key_exchange(3, 353)) self.assertFalse(diffie_hellman_key_exchange(5, 211)) self.assertTrue(diffie_hellman_key_exchange(11, 971)) + if __name__ == "__main__": unittest.main() - From a0cd48b16f2e7ee6d68ac44d982184cf2552a26f Mon Sep 17 00:00:00 2001 From: ShimoniSinha2019H1030019G <73049785+ShimoniSinha2019H1030019G@users.noreply.github.com> Date: Mon, 2 Nov 2020 09:05:51 +0530 Subject: [PATCH 239/302] Construct full binary tree from preorder and postorder traversal (#736) * Construct full binary tree from preorder and postorder * Construct full binary tree from preorder and postorder * Construct full binary tree from preorder and postorder * Construct full binary tree from preorder and postorder * Construct full binary tree from preorder and postorder * added unit test to test_tree.py and changed to snake case to name cariables and functions * added unit test to test_tree.py and changed to snake case to name cariables and functions * added unit test to test_tree.py and changed to snake case to name cariables and functions --- README.md | 1 + algorithms/tree/__init__.py | 0 .../tree/construct_tree_postorder_preorder.py | 111 ++++++++++++++++++ tests/test_tree.py | 30 +++++ 4 files changed, 142 insertions(+) create mode 100644 algorithms/tree/__init__.py create mode 100644 algorithms/tree/construct_tree_postorder_preorder.py diff --git a/README.md b/README.md index bcd135f90..5fabbbe2e 100644 --- a/README.md +++ b/README.md @@ -375,6 +375,7 @@ If you want to uninstall algorithms, it is as simple as: - [b_tree](algorithms/tree/b_tree.py) - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) + - [construct_tree_preorder_postorder](algorithms/tree/construct_tree_postorder_preorder.py) - [deepest_left](algorithms/tree/deepest_left.py) - [invert_tree](algorithms/tree/invert_tree.py) - [is_balanced](algorithms/tree/is_balanced.py) diff --git a/algorithms/tree/__init__.py b/algorithms/tree/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/algorithms/tree/construct_tree_postorder_preorder.py b/algorithms/tree/construct_tree_postorder_preorder.py new file mode 100644 index 000000000..a1bc1688a --- /dev/null +++ b/algorithms/tree/construct_tree_postorder_preorder.py @@ -0,0 +1,111 @@ +""" + Given two arrays representing preorder and postorder traversal of a full + binary tree, construct the binary tree and print the inorder traversal of the + tree. + A full binary tree has either 0 or 2 children. + Algorithm: + 1. Assign the first element of preorder array as root of the tree. + 2. Find the same element in the postorder array and divide the postorder + array into left and right subtree. + 3. Repeat the above steps for all the elements and construct the tree. + Eg: pre[] = {1, 2, 4, 8, 9, 5, 3, 6, 7} + post[] = {8, 9, 4, 5, 2, 6, 7, 3, 1} + Tree: + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 + / \ + 8 9 + Output: 8 4 9 2 5 1 6 3 7 +""" + +class TreeNode: + + def __init__(self, val, left = None, right = None): + self.val = val + self.left = left + self.right = right + +pre_index = 0 + +def construct_tree_util(pre: list, post: list, low: int, high: int, size: int): + """ + Recursive function that constructs tree from preorder and postorder array. + + preIndex is a global variable that keeps track of the index in preorder + array. + preorder and postorder array are represented are pre[] and post[] respectively. + low and high are the indices for the postorder array. + """ + + global pre_index + + if pre_index == -1: + pre_index = 0 + + + #Base case + if(pre_index >= size or low > high): + return None + + root = TreeNode(pre[pre_index]) + pre_index += 1 + + #If only one element in the subarray return root + if(low == high or pre_index >= size): + return root + + #Find the next element of pre[] in post[] + i = low + while i <= high: + if(pre[pre_index] == post[i]): + break + + i += 1 + + #Use index of element present in postorder to divide postorder array + #to two parts: left subtree and right subtree + if(i <= high): + root.left = construct_tree_util(pre, post, low, i, size) + root.right = construct_tree_util(pre, post, i+1, high, size) + + return root + + +def construct_tree(pre: list, post: list, size: int): + """ + Main Function that will construct the full binary tree from given preorder + and postorder array. + """ + + global pre_index + root = construct_tree_util(pre, post, 0, size-1, size) + + return print_inorder(root) + + + +def print_inorder(root: TreeNode, result = None): + """ + Prints the tree constructed in inorder format + """ + if root is None: + return [] + if result is None: + result = [] + + print_inorder(root.left, result) + result.append(root.val) + print_inorder(root.right, result) + return result + +if __name__ == '__main__': + pre = [1, 2, 4, 5, 3, 6, 7] + post = [4, 5, 2, 6, 7, 3, 1] + size = len(pre) + + result = construct_tree(pre, post, size) + + print(result) diff --git a/tests/test_tree.py b/tests/test_tree.py index 912496f8a..1a2863ac7 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -8,6 +8,8 @@ ) from algorithms.tree.b_tree import BTree +from algorithms.tree import construct_tree_postorder_preorder as ctpp + import unittest @@ -107,6 +109,34 @@ def test_deletion_odd_degree(self): self.assertEqual(btree.root.keys, []) self.assertEqual(btree.root.children, []) +class TestConstructTreePreorderPostorder(unittest.TestCase): + def test_construct_tree(self): + + # Test 1 + ctpp.pre_index = 0 + pre1 = [1, 2, 4, 8, 9, 5, 3, 6, 7] + post1 = [8, 9, 4, 5, 2, 6, 7, 3, 1] + size1 = len(pre1) + + self.assertEqual(ctpp.construct_tree(pre1, post1, size1), [8,4,9,2,5,1,6,3,7]) + + # Test 2 + ctpp.pre_index = 0 + pre2 = [1, 2, 4, 5, 3, 6, 7] + post2 = [4, 5, 2, 6, 7, 3, 1] + size2 = len(pre2) + + self.assertEqual(ctpp.construct_tree(pre2, post2, size2), [4,2,5,1,6,3,7]) + + # Test 3 + ctpp.pre_index = 0 + pre3 = [12, 7, 16, 21, 5, 1, 9] + post3 = [16, 21, 7, 1, 9, 5, 12] + size3 = len(pre3) + + self.assertEqual(ctpp.construct_tree(pre3, post3, size3), [16,7,21,12,1,5,9]) + + if __name__ == '__main__': unittest.main() From 9b320bfc972cf8d5e7b8d6b27464ccc527b1da66 Mon Sep 17 00:00:00 2001 From: Erick Lara Date: Sun, 1 Nov 2020 23:47:07 -0600 Subject: [PATCH 240/302] Sort matrix diagonally using heaps. (#665) --- README.md | 1 + algorithms/matrix/sort_matrix_diagonally.py | 77 +++++++++++++++++++++ tests/test_matrix.py | 75 +++++++++++++------- 3 files changed, 128 insertions(+), 25 deletions(-) create mode 100644 algorithms/matrix/sort_matrix_diagonally.py diff --git a/README.md b/README.md index 5fabbbe2e..f08c6d652 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ If you want to uninstall algorithms, it is as simple as: - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py) - [cholesky_matrix_decomposition](algorithms/matrix/cholesky_matrix_decomposition.py) - [sum_sub_squares](algorithms/matrix/sum_sub_squares.py) + - [sort_matrix_diagonally](algorithms/matrix/sort_matrix_diagonally.py) - [queues](algorithms/queues) - [max_sliding_window](algorithms/queues/max_sliding_window.py) - [moving_average](algorithms/queues/moving_average.py) diff --git a/algorithms/matrix/sort_matrix_diagonally.py b/algorithms/matrix/sort_matrix_diagonally.py new file mode 100644 index 000000000..4e9e085d6 --- /dev/null +++ b/algorithms/matrix/sort_matrix_diagonally.py @@ -0,0 +1,77 @@ +""" +Given a m * n matrix mat of integers, +sort it diagonally in ascending order +from the top-left to the bottom-right +then return the sorted array. + +mat = [ + [3,3,1,1], + [2,2,1,2], + [1,1,1,2] +] + +Should return: +[ + [1,1,1,1], + [1,2,2,2], + [1,2,3,3] +] +""" + +from heapq import heappush, heappop +from typing import List + + +def sort_diagonally(mat: List[List[int]]) -> List[List[int]]: + # If the input is a vector, return the vector + if len(mat) == 1 or len(mat[0]) == 1: + return mat + + # Rows + columns - 1 + # The -1 helps you to not repeat a column + for i in range(len(mat)+len(mat[0])-1): + # Process the rows + if i+1 < len(mat): + # Initialize heap, set row and column + h = [] + row = len(mat)-(i+1) + col = 0 + + # Traverse diagonally, and add the values to the heap + while row < len(mat): + heappush(h, (mat[row][col])) + row += 1 + col += 1 + + # Sort the diagonal + row = len(mat)-(i+1) + col = 0 + while h: + ele = heappop(h) + mat[row][col] = ele + row += 1 + col += 1 + else: + # Process the columns + # Initialize heap, row and column + h = [] + row = 0 + col = i - (len(mat)-1) + + # Traverse Diagonally + while col < len(mat[0]) and row < len(mat): + heappush(h, (mat[row][col])) + row += 1 + col += 1 + + # Sort the diagonal + row = 0 + col = i - (len(mat)-1) + while h: + ele = heappop(h) + mat[row][col] = ele + row += 1 + col += 1 + + # Return the updated matrix + return mat diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 88a9b6f73..667dc1670 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -10,7 +10,8 @@ sparse_dot_vector, spiral_traversal, sudoku_validator, - sum_sub_squares + sum_sub_squares, + sort_matrix_diagonally ) import unittest @@ -18,24 +19,24 @@ class TestBombEnemy(unittest.TestCase): def test_3x4(self): grid1 = [ - ["0","E","0","0"], - ["E","0","W","E"], - ["0","E","0","0"] - ] + ["0", "E", "0", "0"], + ["E", "0", "W", "E"], + ["0", "E", "0", "0"] + ] self.assertEqual(3, bomb_enemy.max_killed_enemies(grid1)) grid1 = [ - ["0", "E", "0", "E"], - ["E", "E", "E", "0"], - ["E", "0", "W", "E"], - ["0", "E", "0", "0"] - ] + ["0", "E", "0", "E"], + ["E", "E", "E", "0"], + ["E", "0", "W", "E"], + ["0", "E", "0", "0"] + ] grid2 = [ - ["0", "0", "0", "E"], - ["E", "0", "0", "0"], - ["E", "0", "W", "E"], - ["0", "E", "0", "0"] - ] + ["0", "0", "0", "E"], + ["E", "0", "0", "0"], + ["E", "0", "W", "E"], + ["0", "E", "0", "0"] + ] self.assertEqual(5, bomb_enemy.max_killed_enemies(grid1)) self.assertEqual(3, bomb_enemy.max_killed_enemies(grid2)) @@ -112,7 +113,7 @@ def test_cholesky_matrix_decomposition(self): cholesky_matrix_decomposition.cholesky_decomposition( [[4, 12, -16], [12, 37, -43], [-16, -43, 98]])) - self.assertEqual( None, + self.assertEqual(None, cholesky_matrix_decomposition.cholesky_decomposition( [[4, 12, -8], [12, 4, -43], [-16, -1, 32]])) @@ -123,12 +124,14 @@ def test_cholesky_matrix_decomposition(self): # example taken from https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/04LinearAlgebra/cholesky/ self.assertEqual([[2.23606797749979, 0.0, 0.0, 0.0], [0.5366563145999494, 2.389979079406345, 0.0, 0.0], - [0.13416407864998736, -0.19749126846635062, 2.818332343581848, 0.0], + [0.13416407864998736, -0.19749126846635062, + 2.818332343581848, 0.0], [-0.2683281572999747, 0.43682390737048743, 0.64657701271919, 3.052723872310221]], cholesky_matrix_decomposition.cholesky_decomposition( [[5, 1.2, 0.3, -0.6], [1.2, 6, -0.4, 0.9], [0.3, -0.4, 8, 1.7], [-0.6, 0.9, 1.7, 10]])) + class TestInversion(unittest.TestCase): """[summary] Test for the file matrix_inversion.py @@ -136,11 +139,13 @@ class TestInversion(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_inversion(self): from fractions import Fraction m1 = [[1, 1], [1, 2]] - self.assertEqual(matrix_inversion.invert_matrix(m1), [[2, -1], [-1, 1]]) + self.assertEqual(matrix_inversion.invert_matrix(m1), + [[2, -1], [-1, 1]]) m2 = [[1, 2], [3, 4, 5]] self.assertEqual(matrix_inversion.invert_matrix(m2), [[-1]]) @@ -151,15 +156,17 @@ def test_inversion(self): m4 = [[1]] self.assertEqual(matrix_inversion.invert_matrix(m4), [[-3]]) - m5 = [[1, 2, 3] , [4, 5, 6], [7, 8, 9]] + m5 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] self.assertEqual(matrix_inversion.invert_matrix(m5), [[-4]]) m6 = [[3, 5, 1], [2, 5, 0], [1, 9, 8]] self.assertEqual(matrix_inversion.invert_matrix(m6), [[Fraction(40, 53), Fraction(-31, 53), Fraction(-5, 53)], - [Fraction(-16, 53), Fraction(23, 53), Fraction(2, 53)], + [Fraction(-16, 53), Fraction( + 23, 53), Fraction(2, 53)], [Fraction(13, 53), Fraction(-22, 53), Fraction(5, 53)]]) + class TestMatrixExponentiation(unittest.TestCase): """[summary] Test for the file matrix_exponentiation.py @@ -329,6 +336,7 @@ def test_sudoku_validator(self): [3, 0, 0, 4, 8, 1, 1, 7, 9] ])) + class TestSumSubSquares(unittest.TestCase): """[summary] Test for the file sum_sub_squares.py @@ -336,14 +344,31 @@ class TestSumSubSquares(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + def test_sum_sub_squares(self): - mat = [[1, 1, 1, 1, 1], - [2, 2, 2, 2, 2], - [3, 3, 3, 3, 3], - [4, 4, 4, 4, 4], - [5, 5, 5, 5, 5]] + mat = [[1, 1, 1, 1, 1], + [2, 2, 2, 2, 2], + [3, 3, 3, 3, 3], + [4, 4, 4, 4, 4], + [5, 5, 5, 5, 5]] self.assertEqual(sum_sub_squares.sum_sub_squares(mat, 3), [[18, 18, 18], [27, 27, 27], [36, 36, 36]]) + +class TestSortMatrixDiagonally(unittest.TestCase): + def test_sort_diagonally(self): + mat = [ + [3, 3, 1, 1], + [2, 2, 1, 2], + [1, 1, 1, 2] + ] + + self.assertEqual(sort_matrix_diagonally.sort_diagonally(mat), [ + [1, 1, 1, 1], + [1, 2, 2, 2], + [1, 2, 3, 3] + ]) + + if __name__ == "__main__": unittest.main() From 8ebe8b55c9abfedce1f60c16b9f283dce3133db5 Mon Sep 17 00:00:00 2001 From: ShimoniSinha2019H1030019G <73049785+ShimoniSinha2019H1030019G@users.noreply.github.com> Date: Fri, 6 Nov 2020 23:16:03 +0530 Subject: [PATCH 241/302] Added implementation of fenwick tree (#739) * Added implementation of fenwick tree in the tree folder * Converted into data structure and removed main function. Created a new directory in the tree directory to store the python file. * Converted into data structure and removed main function. Created a new directory in the tree directory to store the python file. * Converted into data structure and removed main function. Created a new directory in the tree directory to store the python file. --- README.md | 2 + algorithms/tree/fenwick_tree/fenwick_tree.py | 77 ++++++++++++++++++++ tests/__init__.py | 0 tests/test_tree.py | 32 ++++++++ 4 files changed, 111 insertions(+) create mode 100644 algorithms/tree/fenwick_tree/fenwick_tree.py delete mode 100644 tests/__init__.py diff --git a/README.md b/README.md index f08c6d652..a883f9f49 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,8 @@ If you want to uninstall algorithms, it is as simple as: - [count_left_node](algorithms/tree/bst/count_left_node.py) - [num_empty](algorithms/tree/bst/num_empty.py) - [height](algorithms/tree/bst/height.py) + - [fenwick_tree](algorithms/tree/fenwick_tree] + - [fenwick_tree](algorithms/tree/fenwick_tree/fenwick_tree.py) - [red_black_tree](algorithms/tree/red_black_tree) - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - [segment_tree](algorithms/tree/segment_tree) diff --git a/algorithms/tree/fenwick_tree/fenwick_tree.py b/algorithms/tree/fenwick_tree/fenwick_tree.py new file mode 100644 index 000000000..67ec5105e --- /dev/null +++ b/algorithms/tree/fenwick_tree/fenwick_tree.py @@ -0,0 +1,77 @@ +""" +Fenwick Tree / Binary Indexed Tree + +Consider we have an array arr[0 . . . n-1]. We would like to +1. Compute the sum of the first i elements. +2. Modify the value of a specified element of the array arr[i] = x where 0 <= i <= n-1. + +A simple solution is to run a loop from 0 to i-1 and calculate the sum of the elements. To update a value, simply do arr[i] = x. +The first operation takes O(n) time and the second operation takes O(1) time. +Another simple solution is to create an extra array and store the sum of the first i-th elements at the i-th index in this new array. +The sum of a given range can now be calculated in O(1) time, but the update operation takes O(n) time now. +This works well if there are a large number of query operations but a very few number of update operations. + + +There are two solutions that can perform both the query and update operations in O(logn) time. +1. Fenwick Tree +2. Segment Tree + +Compared with Segment Tree, Binary Indexed Tree requires less space and is easier to implement. +""" + +class Fenwick_Tree(object): + def __init__(self, freq): + self.arr = freq + self.n = len(freq) + + def get_sum(self, bit_tree, i): + """ + Returns sum of arr[0..index]. This function assumes that the array is preprocessed and partial sums of array elements are stored in bit_tree[]. + """ + + s = 0 + + # index in bit_tree[] is 1 more than the index in arr[] + i = i+1 + + # Traverse ancestors of bit_tree[index] + while i > 0: + + # Add current element of bit_tree to sum + s += bit_tree[i] + + # Move index to parent node in getSum View + i -= i & (-i) + return s + + def update_bit(self, bit_tree, i, v): + """ + Updates a node in Binary Index Tree (bit_tree) at given index in bit_tree. The given value 'val' is added to bit_tree[i] and all of its ancestors in tree. + """ + + # index in bit_ree[] is 1 more than the index in arr[] + i += 1 + + # Traverse all ancestors and add 'val' + while i <= self.n: + + # Add 'val' to current node of bit_tree + bit_tree[i] += v + + # Update index to that of parent in update View + i += i & (-i) + + + def construct(self): + """ + Constructs and returns a Binary Indexed Tree for given array of size n. + """ + + # Create and initialize bit_ree[] as 0 + bit_tree = [0]*(self.n+1) + + # Store the actual values in bit_ree[] using update() + for i in range(self.n): + self.update_bit(bit_tree, i, self.arr[i]) + + return bit_tree diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/test_tree.py b/tests/test_tree.py index 1a2863ac7..170a931dd 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -10,6 +10,8 @@ from algorithms.tree import construct_tree_postorder_preorder as ctpp +from algorithms.tree.fenwick_tree.fenwick_tree import Fenwick_Tree + import unittest @@ -137,6 +139,36 @@ def test_construct_tree(self): self.assertEqual(ctpp.construct_tree(pre3, post3, size3), [16,7,21,12,1,5,9]) +class TestFenwickTree(unittest.TestCase): + def test_construct_tree_with_update_1(self): + freq = [2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9] + ft = Fenwick_Tree(freq) + bit_tree = ft.construct() + self.assertEqual(12, ft.get_sum(bit_tree, 5)) + + freq[3] += 6 + ft.update_bit(bit_tree, 3, 6) + self.assertEqual(18, ft.get_sum(bit_tree, 5)) + + def test_construct_tree_with_update_2(self): + freq = [1, 2, 3, 4, 5] + ft = Fenwick_Tree(freq) + bit_tree = ft.construct() + self.assertEqual(10, ft.get_sum(bit_tree, 3)) + + freq[3] -= 5 + ft.update_bit(bit_tree, 3, -5) + self.assertEqual(5, ft.get_sum(bit_tree, 3)) + + def test_construct_tree_with_update_3(self): + freq = [2, 1, 4, 6, -1, 5, -32, 0, 1] + ft = Fenwick_Tree(freq) + bit_tree = ft.construct() + self.assertEqual(12, ft.get_sum(bit_tree, 4)) + + freq[2] += 11 + ft.update_bit(bit_tree, 2, 11) + self.assertEqual(23, ft.get_sum(bit_tree, 4)) if __name__ == '__main__': unittest.main() From 2dbf296f558b61798fabd0b5f84fa761b609a68e Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 17 Nov 2020 18:56:44 +0000 Subject: [PATCH 242/302] finding number of digits using logs created with unit tests --- .gitignore | 2 +- algorithms/maths/__init__.py | 1 + algorithms/maths/num_digits.py | 10 ++++++++++ tests/test_maths.py | 15 ++++++++++++++- 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 algorithms/maths/num_digits.py diff --git a/.gitignore b/.gitignore index fbcdee784..6ca05bc23 100755 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,5 @@ __pycache__/ /*.egg # docs build/ - +pythonenv3.8/ .vscode/ diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 7b8a7b1ec..60a371239 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -18,3 +18,4 @@ from .find_order_simple import * from .find_primitive_root_simple import * from .diffie_hellman_key_exchange import * +from .num_digits import * diff --git a/algorithms/maths/num_digits.py b/algorithms/maths/num_digits.py new file mode 100644 index 000000000..e8373d14b --- /dev/null +++ b/algorithms/maths/num_digits.py @@ -0,0 +1,10 @@ +""" + num_digits() method will return the number of digits of a number in O(1) time using math.log10() method. +""" + +import math + +def num_digits(n): + if(n==0): + return 1; + return int(math.log10(n))+1 diff --git a/tests/test_maths.py b/tests/test_maths.py index c29a8664a..cc270d5ab 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -19,7 +19,8 @@ cosine_similarity, find_order, find_primitive_root, - alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange + alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, + num_digits ) import unittest @@ -369,6 +370,18 @@ def test_find_order_simple(self): self.assertFalse(diffie_hellman_key_exchange(5, 211)) self.assertTrue(diffie_hellman_key_exchange(11, 971)) +class TestNumberOfDigits(unittest.TestCase): + """[summary] + Test for the file num_digits.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_num_digits(self): + self.assertEqual(2,num_digits(12)) + self.assertEqual(5,num_digits(99999)) + self.assertEqual(1,num_digits(8)) + if __name__ == "__main__": unittest.main() From 52e94a5624b2101e00ebcabf280265b9cea9c9ce Mon Sep 17 00:00:00 2001 From: Vignesh Date: Wed, 18 Nov 2020 09:39:16 +0530 Subject: [PATCH 243/302] Update test_maths.py --- tests/test_maths.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_maths.py b/tests/test_maths.py index a8b097bcb..4ed370a1a 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -23,7 +23,7 @@ find_order, find_primitive_root, alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, - num_digits + num_digits, alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, krishnamurthy_number ) From 6ce5feaa745e2c94ac58f8c9f1853de9138aabc7 Mon Sep 17 00:00:00 2001 From: Aalekh Patel Date: Sun, 22 Nov 2020 09:22:43 -0600 Subject: [PATCH 244/302] Add Polynomials (DS) + Unit tests, and Cycle Index Polynomial for Symmetry Groups (Algorithm) (#741) * Put proper parenthesis for expected output. * Add the Monomial and Polynomial Data Structure for symbolic computation. * Add an algorithm to generate the cycle index polynomial for Symmetry Group on n symbols. * Add multiple Unit Tests for every Polynomial and Monomial operation. * Revert the parenthesis change because it didn't add much value. * Fix typo that introduced a Syntax Error. * Remove future annotations because of incompatibility of postponed evaluation of annotations in Python <= 3.6. * Add record for Polynomial and symmetry group index. Rearrange records to be alphabetical. Co-authored-by: aalekhpatel07 --- README.md | 16 +- algorithms/maths/gcd.py | 4 +- algorithms/maths/polynomial.py | 534 ++++++++++++++++++ .../maths/symmetry_group_cycle_index.py | 162 ++++++ tests/test_monomial.py | 206 +++++++ tests/test_polynomial.py | 175 ++++++ 6 files changed, 1088 insertions(+), 9 deletions(-) create mode 100644 algorithms/maths/polynomial.py create mode 100644 algorithms/maths/symmetry_group_cycle_index.py create mode 100644 tests/test_monomial.py create mode 100644 tests/test_polynomial.py diff --git a/README.md b/README.md index a883f9f49..e192204e2 100644 --- a/README.md +++ b/README.md @@ -198,36 +198,38 @@ If you want to uninstall algorithms, it is as simple as: - [is_isomorphic](algorithms/map/is_isomorphic.py) - [is_anagram](algorithms/map/is_anagram.py) - [maths](algorithms/maths) - - [power](algorithms/maths/power.py) - [base_conversion](algorithms/maths/base_conversion.py) - [combination](algorithms/maths/combination.py) - [cosine_similarity](algorithms/maths/cosine_similarity.py) - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) + - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) - [euler_totient](algorithms/maths/euler_totient.py) - [extended_gcd](algorithms/maths/extended_gcd.py) - [factorial](algorithms/maths/factorial.py) + - [find_order](algorithms/maths/find_order_simple.py) + - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - [gcd/lcm](algorithms/maths/gcd.py) - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [hailstone](algorithms/maths/hailstone.py) - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [magic_number](algorithms/maths/magic_number.py) - [krishnamurthy_number](algorithms/maths/krishnamurthy_number.py) + - [magic_number](algorithms/maths/magic_number.py) - [modular_exponential](algorithms/maths/modular_exponential.py) - [modular_inverse](algorithms/maths/modular_inverse.py) - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) + - [polynomial](algorithms/maths/polynomial.py) + - [power](algorithms/maths/power.py) - [prime_check](algorithms/maths/prime_check.py) - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - [pythagoras](algorithms/maths/pythagoras.py) - [rabin_miller](algorithms/maths/rabin_miller.py) + - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) - [rsa](algorithms/maths/rsa.py) - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - [summing_digits](algorithms/maths/summing_digits.py) - - [hailstone](algorithms/maths/hailstone.py) - - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) - - [find_order](algorithms/maths/find_order_simple.py) - - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) + - [symmetry_group_cycle_index](algorithms/maths/symmetry_group_cycle_index.py) - [matrix](algorithms/matrix) - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - [bomb_enemy](algorithms/matrix/bomb_enemy.py) diff --git a/algorithms/maths/gcd.py b/algorithms/maths/gcd.py index 002f4fcd3..abc2814dd 100644 --- a/algorithms/maths/gcd.py +++ b/algorithms/maths/gcd.py @@ -32,7 +32,7 @@ def trailing_zero(x): return cnt """ -Given two non-negative integer a and b, +Given two non-negative integer a and b, computes the greatest common divisor of a and b using bitwise operator. """ @@ -42,7 +42,7 @@ def gcd_bit(a, b): a >>= tza b >>= tzb while b: - if a < b: + if a < b: a, b = b, a a -= b a >>= trailing_zero(a) diff --git a/algorithms/maths/polynomial.py b/algorithms/maths/polynomial.py new file mode 100644 index 000000000..55b59dd91 --- /dev/null +++ b/algorithms/maths/polynomial.py @@ -0,0 +1,534 @@ +# from __future__ import annotations + +from fractions import Fraction +from typing import Dict, Union, Set, Iterable +from numbers import Rational +from functools import reduce + + +class Monomial: + """ + A simple Monomial class to + record the details of all variables + that a typical monomial is composed of. + """ + def __init__(self, variables: Dict[int, int], coeff: Union[int, float, Fraction, None]=None) -> None: + ''' + Create a monomial in the given variables: + Examples: + + Monomial({1:1}) = (a_1)^1 + + Monomial({ + 1:3, + 2:2, + 4:1, + 5:0 + }, 12) = 12(a_1)^3(a_2)^2(a_4) + + Monomial({}) = 0 + + Monomial({2:3, 3:-1}, 1.5) = (3/2)(a_2)^3(a_3)^(-1) + + ''' + self.variables = dict() + + if coeff is None: + if len(variables) == 0: + coeff = Fraction(0, 1) + else: + coeff = Fraction(1, 1) + elif coeff == 0: + self.coeff = Fraction(0, 1) + return + + if len(variables) == 0: + self.coeff = Monomial._rationalize_if_possible(coeff) + return + + for i in variables: + if variables[i] != 0: + self.variables[i] = variables[i] + self.coeff = Monomial._rationalize_if_possible(coeff) + + @staticmethod + def _rationalize_if_possible(num): + ''' + A helper for converting numbers + to Fraction only when possible. + ''' + if isinstance(num, Rational): + res = Fraction(num, 1) + return Fraction(res.numerator, res.denominator) + else: + return num + + + # def equal_upto_scalar(self, other: Monomial) -> bool: + def equal_upto_scalar(self, other) -> bool: + """ + Return True if other is a monomial + and is equivalent to self up to a scalar + multiple. + """ + if not isinstance(other, Monomial): + raise ValueError('Can only compare monomials.') + return other.variables == self.variables + + # def __add__(self, other: Union[int, float, Fraction, Monomial]): + def __add__(self, other: Union[int, float, Fraction]): + """ + Define the addition of two + monomials or the addition of + a monomial with an int, float, or a Fraction. + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + return self.__add__(Monomial({}, Monomial._rationalize_if_possible(other))) + + if not isinstance(other, Monomial): + raise ValueError('Can only add monomials, ints, floats, or Fractions.') + + if self.variables == other.variables: + mono = {i: self.variables[i] for i in self.variables} + return Monomial(mono, Monomial._rationalize_if_possible(self.coeff + other.coeff)).clean() + + # If they don't share same variables then by the definition, + # if they are added, the result becomes a polynomial and not a monomial. + # Thus, raise ValueError in that case. + + raise ValueError(f'Cannot add {str(other)} to {self.__str__()} because they don\'t have same variables.') + + # def __eq__(self, other: Monomial) -> bool: + def __eq__(self, other) -> bool: + """ + Return True if two monomials + are equal upto a scalar multiple. + """ + return self.equal_upto_scalar(other) and self.coeff == other.coeff + + # def __mul__(self, other: Union[int, float, Fraction, Monomial]) -> Monomial: + def __mul__(self, other: Union[int, float, Fraction]): + """ + Multiply two monomials and merge the variables + in both of them. + + Examples: + + Monomial({1:1}) * Monomial({1: -3, 2: 1}) = (a_1)^(-2)(a_2) + Monomial({3:2}) * 2.5 = (5/2)(a_3)^2 + + """ + if isinstance(other, float) or isinstance(other, int) or isinstance(other, Fraction): + mono = {i: self.variables[i] for i in self.variables} + return Monomial(mono, Monomial._rationalize_if_possible(self.coeff * other)).clean() + + if not isinstance(other, Monomial): + raise ValueError('Can only multiply monomials, ints, floats, or Fractions.') + else: + mono = {i: self.variables[i] for i in self.variables} + for i in other.variables: + if i in mono: + mono[i] += other.variables[i] + else: + mono[i] = other.variables[i] + + temp = dict() + for k in mono: + if mono[k] != 0: + temp[k] = mono[k] + + return Monomial(temp, Monomial._rationalize_if_possible(self.coeff * other.coeff)).clean() + + # def inverse(self) -> Monomial: + def inverse(self): + """ + Compute the inverse of a monomial. + + Examples: + + Monomial({1:1, 2:-1, 3:2}, 2.5).inverse() = Monomial({1:-1, 2:1, 3:-2} ,2/5) + + + """ + mono = {i: self.variables[i] for i in self.variables if self.variables[i] != 0} + for i in mono: + mono[i] *= -1 + if self.coeff == 0: + raise ValueError("Coefficient must not be 0.") + return Monomial(mono, Monomial._rationalize_if_possible(1/self.coeff)).clean() + + # def __truediv__(self, other: Union[int, float, Fraction, Monomial]) -> Monomial: + def __truediv__(self, other: Union[int, float, Fraction]): + """ + Compute the division between two monomials + or a monomial and some other datatype + like int/float/Fraction. + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + mono = {i: self.variables[i] for i in self.variables} + if other == 0: + raise ValueError('Cannot divide by 0.') + return Monomial(mono, Monomial._rationalize_if_possible(self.coeff / other)).clean() + + o = other.inverse() + return self.__mul__(o) + + # def __floordiv__(self, other: Union[int, float, Fraction, Monomial]) -> Monomial: + def __floordiv__(self, other: Union[int, float, Fraction]): + """ + For monomials, + floor div is the same as true div. + """ + return self.__truediv__(other) + + # def clone(self) -> Monomial: + def clone(self): + """ + Clone the monomial. + """ + temp_variables = {i: self.variables[i] for i in self.variables} + return Monomial(temp_variables, Monomial._rationalize_if_possible(self.coeff)).clean() + + # def clean(self) -> Monomial: + def clean(self): + """ + Clean the monomial by dropping any variables that have power 0. + """ + temp_variables = {i: self.variables[i] for i in self.variables if self.variables[i] != 0} + return Monomial(temp_variables, Monomial._rationalize_if_possible(self.coeff)) + + # def __sub__(self, other: Union[int, float, Fraction, Monomial]) -> Monomial: + def __sub__(self, other: Union[int, float, Fraction]): + """ + Compute the subtraction + of a monomial and a datatype + such as int, float, Fraction, or Monomial. + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + mono = {i: self.variables[i] for i in self.variables if self.variables[i] != 0} + if len(mono) != 0: + raise ValueError('Can only subtract like monomials.') + other_term = Monomial(mono, Monomial._rationalize_if_possible(other)) + return self.__sub__(other_term) + if not isinstance(other, Monomial): + raise ValueError('Can only subtract monomials') + return self.__add__(other.__mul__(Fraction(-1, 1))) + + def __hash__(self) -> int: + """ + Define the hash of a monomial + by the underlying variables. + + If hashing is implemented in O(v*log(v)) + where v represents the number of + variables in the monomial, + then search queries for the + purposes of simplification of a + polynomial can be performed in + O(v*log(v)) as well; much better than + the length of the polynomial. + """ + arr = [] + for i in sorted(self.variables): + if self.variables[i] > 0: + for _ in range(self.variables[i]): + arr.append(i) + return hash(tuple(arr)) + + def all_variables(self) -> Set: + """ + Get the set of all variables + present in the monomial. + """ + return set(sorted(self.variables.keys())) + + def substitute(self, substitutions: Union[int, float, Fraction, Dict[int, Union[int, float, Fraction]]]) -> Fraction: + """ + Substitute the variables in the + monomial for values defined by + the substitutions dictionary. + """ + if isinstance(substitutions, int) or isinstance(substitutions, float) or isinstance(substitutions, Fraction): + substitutions = {v: Monomial._rationalize_if_possible(substitutions) for v in self.all_variables()} + else: + if not self.all_variables().issubset(set(substitutions.keys())): + raise ValueError('Some variables didn\'t receive their values.') + if self.coeff == 0: + return Fraction(0, 1) + ans = Monomial._rationalize_if_possible(self.coeff) + for k in self.variables: + ans *= Monomial._rationalize_if_possible(substitutions[k]**self.variables[k]) + return Monomial._rationalize_if_possible(ans) + + def __str__(self) -> str: + """ + Get a string representation of + the monomial. + """ + if len(self.variables) == 0: + return str(self.coeff) + + result = str(self.coeff) + result += '(' + for i in self.variables: + temp = 'a_{}'.format(str(i)) + if self.variables[i] > 1: + temp = '(' + temp + ')**{}'.format(self.variables[i]) + elif self.variables[i] < 0: + temp = '(' + temp + ')**(-{})'.format(-self.variables[i]) + elif self.variables[i] == 0: + continue + else: + temp = '(' + temp + ')' + result += temp + return result + ')' + + +class Polynomial: + """ + A simple implementation + of a polynomial class that + records the details about two polynomials + that are potentially comprised of multiple + variables. + """ + def __init__(self, monomials: Iterable[Union[int, float, Fraction, Monomial]]) -> None: + ''' + Create a polynomial in the given variables: + Examples: + + Polynomial([ + Monomial({1:1}, 2), + Monomial({2:3, 1:-1}, -1), + math.pi, + Fraction(-1, 2) + ]) = (a_1)^2 + (-1)(a_2)^3(a_1)^(-1) + 2.6415926536 + + Polynomial([]) = 0 + + ''' + self.monomials = set() + for m in monomials: + if any(map(lambda x: isinstance(m, x), [int, float, Fraction])): + self.monomials |= {Monomial({}, m)} + elif isinstance(m, Monomial): + self.monomials |= {m} + else: + raise ValueError('Iterable should have monomials, int, float, or Fraction.') + self.monomials -= {Monomial({}, 0)} + + @staticmethod + def _rationalize_if_possible(num): + ''' + A helper for converting numbers + to Fraction only when possible. + ''' + if isinstance(num, Rational): + res = Fraction(num, 1) + return Fraction(res.numerator, res.denominator) + else: + return num + + + # def __add__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: + def __add__(self, other: Union[int, float, Fraction, Monomial]): + """ + Add a given poylnomial to a copy of self. + + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + return self.__add__(Monomial({}, Polynomial._rationalize_if_possible(other))) + elif isinstance(other, Monomial): + monos = {m.clone() for m in self.monomials} + + for _own_monos in monos: + if _own_monos.equal_upto_scalar(other): + scalar = _own_monos.coeff + monos -= {_own_monos} + temp_variables = {i: other.variables[i] for i in other.variables} + monos |= {Monomial(temp_variables, Polynomial._rationalize_if_possible(scalar + other.coeff))} + return Polynomial([z for z in monos]) + + monos |= {other.clone()} + return Polynomial([z for z in monos]) + elif isinstance(other, Polynomial): + temp = list(z for z in {m.clone() for m in self.all_monomials()}) + + p = Polynomial(temp) + for o in other.all_monomials(): + p = p.__add__(o.clone()) + return p + else: + raise ValueError('Can only add int, float, Fraction, Monomials, or Polynomials to Polynomials.') + + # def __sub__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: + def __sub__(self, other: Union[int, float, Fraction, Monomial]): + """ + Subtract the given polynomial + from a copy of self. + + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + return self.__sub__(Monomial({}, Polynomial._rationalize_if_possible(other))) + elif isinstance(other, Monomial): + monos = {m.clone() for m in self.all_monomials()} + for _own_monos in monos: + if _own_monos.equal_upto_scalar(other): + scalar = _own_monos.coeff + monos -= {_own_monos} + temp_variables = {i: other.variables[i] for i in other.variables} + monos |= {Monomial(temp_variables, Polynomial._rationalize_if_possible(scalar - other.coeff))} + return Polynomial([z for z in monos]) + + to_insert = other.clone() + to_insert.coeff *= -1 + + monos |= {to_insert} + return Polynomial([z for z in monos]) + + elif isinstance(other, Polynomial): + p = Polynomial(list(z for z in {m.clone() for m in self.all_monomials()})) + for o in other.all_monomials(): + p = p.__sub__(o.clone()) + return p + + else: + raise ValueError('Can only subtract int, float, Fraction, Monomials, or Polynomials from Polynomials.') + return + + # def __mul__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: + def __mul__(self, other: Union[int, float, Fraction, Monomial]): + """ + Multiply a given polynomial + to a copy of self. + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + result = Polynomial([]) + monos = {m.clone() for m in self.all_monomials()} + for m in monos: + result = result.__add__(m.clone()*other) + return result + elif isinstance(other, Monomial): + result = Polynomial([]) + monos = {m.clone() for m in self.all_monomials()} + for m in monos: + result = result.__add__(m.clone() * other) + return result + elif isinstance(other, Polynomial): + temp_self = {m.clone() for m in self.all_monomials()} + temp_other = {m.clone() for m in other.all_monomials()} + + result = Polynomial([]) + + for i in temp_self: + for j in temp_other: + result = result.__add__(i * j) + + return result + else: + raise ValueError('Can only multiple int, float, Fraction, Monomials, or Polynomials with Polynomials.') + + # def __floordiv__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: + def __floordiv__(self, other: Union[int, float, Fraction, Monomial]): + """ + For Polynomials, floordiv is the same + as truediv. + """ + return self.__truediv__(other) + + # def __truediv__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: + def __truediv__(self, other: Union[int, float, Fraction, Monomial]): + """ + For Polynomials, only division by a monomial + is defined. + + TODO: Implement polynomial / polynomial. + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + return self.__truediv__( Monomial({}, other) ) + elif isinstance(other, Monomial): + poly_temp = reduce(lambda acc, val: acc + val, map(lambda x: x / other, [z for z in self.all_monomials()]), Polynomial([Monomial({}, 0)])) + return poly_temp + elif isinstance(other, Polynomial): + if Monomial({}, 0) in other.all_monomials(): + if len(other.all_monomials()) == 2: + temp_set = {x for x in other.all_monomials() if x != Monomial({}, 0)} + only = temp_set.pop() + return self.__truediv__(only) + elif len(other.all_monomials()) == 1: + temp_set = {x for x in other.all_monomials()} + only = temp_set.pop() + return self.__truediv__(only) + + raise ValueError('Can only divide a polynomial by an int, float, Fraction, or a Monomial.') + + return + + # def clone(self) -> Polynomial: + def clone(self): + """ + Clone the polynomial. + """ + return Polynomial(list({m.clone() for m in self.all_monomials()})) + + def variables(self) -> Set: + """ + Get all the variables present + in this polynomials. + """ + res = set() + for i in self.all_monomials(): + res |= {j for j in i.variables} + res = list(res) + # res.sort() + return set(res) + + def all_monomials(self) -> Iterable[Monomial]: + """ + Get the monomials of this polynomial. + """ + return {m for m in self.monomials if m != Monomial({}, 0)} + + + def __eq__(self, other) -> bool: + """ + Return True if the other polynomial is the same as + this. + """ + if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): + other_poly = Polynomial([Monomial({}, other)]) + return self.__eq__(other_poly) + elif isinstance(other, Monomial): + return self.__eq__(Polynomial([other])) + elif isinstance(other, Polynomial): + return self.all_monomials() == other.all_monomials() + else: + raise ValueError('Can only compare a polynomial with an int, float, Fraction, Monomial, or another Polynomial.') + + + def subs(self, substitutions: Union[int, float, Fraction, Dict[int, Union[int, float, Fraction]]]) -> Union[int, float, Fraction]: + """ + Get the value after substituting + certain values for the variables + defined in substitutions. + """ + if isinstance(substitutions, int) or isinstance(substitutions, float) or isinstance(substitutions, Fraction): + substitutions = {i: Polynomial._rationalize_if_possible(substitutions) for i in set(self.variables())} + return self.subs(substitutions) + elif not isinstance(substitutions, dict): + raise ValueError('The substitutions should be a dictionary.') + if not self.variables().issubset(set(substitutions.keys())): + raise ValueError('Some variables didn\'t receive their values.') + + ans = 0 + for m in self.all_monomials(): + ans += Polynomial._rationalize_if_possible(m.substitute(substitutions)) + return Polynomial._rationalize_if_possible(ans) + + def __str__(self) -> str: + """ + Get a string representation of + the polynomial. + """ + return ' + '.join(str(m) for m in self.all_monomials() if m.coeff != Fraction(0, 1)) + diff --git a/algorithms/maths/symmetry_group_cycle_index.py b/algorithms/maths/symmetry_group_cycle_index.py new file mode 100644 index 000000000..5f3872ac8 --- /dev/null +++ b/algorithms/maths/symmetry_group_cycle_index.py @@ -0,0 +1,162 @@ +from polynomial import ( Monomial, Polynomial ) +from gcd import lcm +from fractions import Fraction +from typing import Dict, Union + + +""" + The significance of the cycle index (polynomial) of symmetry group + is deeply rooted in counting the number of configurations + of an object excluding those that are symmetric (in terms of permutations). + + For example, the following problem can be solved as a direct + application of the cycle index polynomial of the symmetry + group. + + Note: I came across this problem as a Google's foo.bar challenge at Level 5 + and solved it using a purely Group Theoretic approach. :) + + ----- + + Problem: + + Given positive integers + w, h, and s, + compute the number of distinct 2D + grids of dimensions w x h that contain + entries from {0, 1, ..., s-1}. + Note that two grids are defined + to be equivalent if one can be + obtained from the other by + switching rows and columns + some number of times. + + ----- + + Approach: + + Compute the cycle index (polynomials) + of S_w, and S_h, i.e. the Symmetry + group on w and h symbols respectively. + + Compute the product of the two + cycle indices while combining two + monomials in such a way that + for any pair of cycles c1, and c2 + in the elements of S_w X S_h, + the resultant monomial contains + terms of the form: + $$ x_{lcm(|c1|, |c2|)}^{gcd(|c1|, |c2|)} $$ + + Return the specialization of + the product of cycle indices + at x_i = s (for all the valid i). + + ----- + + Code: + + def solve(w, h, s): + + s1 = get_cycle_index_sym(w) + s2 = get_cycle_index_sym(h) + + result = cycle_product_for_two_polynomials(s1, s2, s) + + return str(result) + +""" + +def cycle_product(m1: Monomial, m2: Monomial) -> Monomial: + """ + Given two monomials (from the + cycle index of a symmetry group), + compute the resultant monomial + in the cartesian product + corresponding to their merging. + """ + assert isinstance(m1, Monomial) and isinstance(m2, Monomial) + A = m1.variables + B = m2.variables + result_variables = dict() + for i in A: + for j in B: + k = lcm(i, j) + g = (i * j) // k + if k in result_variables: + result_variables[k] += A[i] * B[j] * g + else: + result_variables[k] = A[i] * B[j] * g + + return Monomial(result_variables, Fraction(m1.coeff * m2.coeff, 1)) + + +def cycle_product_for_two_polynomials(p1: Polynomial, p2: Polynomial, q: Union[float, int, Fraction]) -> Union[float, int, Fraction]: + """ + Compute the product of + given cycle indices p1, + and p2 and evaluate it at q. + """ + ans = Fraction(0, 1) + for m1 in p1.monomials: + for m2 in p2.monomials: + ans += cycle_product(m1, m2).substitute(q) + + return ans + + +def cycle_index_sym_helper(n: int, memo: Dict[int, Polynomial]) -> Polynomial: + """ + A helper for the dp-style evaluation + of the cycle index. + + The recurrence is given in: + https://en.wikipedia.org/wiki/Cycle_index#Symmetric_group_Sn + + """ + if n in memo: + return memo[n] + ans = Polynomial([Monomial({}, Fraction(0, 1))]) + for t in range(1, n+1): + ans = ans.__add__(Polynomial([Monomial({t: 1}, Fraction(1, 1))]) * cycle_index_sym_helper(n-t, memo)) + ans *= Fraction(1, n) + memo[n] = ans + return memo[n] + + +def get_cycle_index_sym(n: int) -> Polynomial: + """ + Compute the cycle index + of S_n, i.e. the symmetry + group of n symbols. + + """ + if n < 0: + raise ValueError('n should be a non-negative integer.') + + memo = { + 0: Polynomial([ + Monomial({}, Fraction(1, 1)) + ]), + 1: Polynomial([ + Monomial({1:1}, Fraction(1, 1)) + ]), + 2: Polynomial([ + Monomial({1: 2}, Fraction(1, 2)), + Monomial({2: 1}, Fraction(1, 2)) + ]), + 3: Polynomial([ + Monomial({1: 3}, Fraction(1, 6)), + Monomial({1: 1, 2: 1}, Fraction(1, 2)), + Monomial({3:1}, Fraction(1, 3)) + ]), + 4: Polynomial([ + Monomial({1:4}, Fraction(1, 24)), + Monomial({2:1, 1:2},Fraction(1, 4)), + Monomial({3:1, 1:1}, Fraction(1, 3)), + Monomial({2:2}, Fraction(1, 8)), + Monomial({4:1}, Fraction(1, 4)), + ]) + } + result = cycle_index_sym_helper(n, memo) + return result diff --git a/tests/test_monomial.py b/tests/test_monomial.py new file mode 100644 index 000000000..8e4667d83 --- /dev/null +++ b/tests/test_monomial.py @@ -0,0 +1,206 @@ +from algorithms.maths.polynomial import Monomial +from fractions import Fraction +import math + + +import unittest + +class TestSuite(unittest.TestCase): + + def setUp(self): + self.m1 = Monomial({}) + self.m2 = Monomial({1: 1}, 2) + self.m3 = Monomial({1: 2, 2: -1}, 1.5) + self.m4 = Monomial({1: 1, 2: 2, 3: -2}, 3) + self.m5 = Monomial({2: 1, 3: 0}, Fraction(2, 3)) + self.m6 = Monomial({1: 0, 2: 0, 3: 0}, -2.27) + self.m7 = Monomial({1: 2, 7: 2}, -math.pi) + self.m8 = Monomial({150: 5, 170: 2, 10000:3}, 0) + self.m9 = 2 + self.m10 = math.pi + self.m11 = Fraction(3, 8) + self.m12 = 0 + self.m13 = Monomial({1: 1}, -2) + self.m14 = Monomial({1: 2}, 3) + self.m15 = Monomial({1: 1}, 3) + self.m16 = Monomial({1: 2, 7: 2}, math.pi) + self.m17 = Monomial({1: -1}) + + def test_monomial_addition(self): + + # Monomials with different underlying variables or + # even different power of those variables must not be added! + self.assertRaises(ValueError, lambda x, y: x + y, self.m1, self.m2) + self.assertRaises(ValueError, lambda x, y: x + y, self.m2, self.m3) + self.assertRaises(ValueError, lambda x, y: x + y, self.m2, self.m14) + + # Additive inverses of each other should produce the zero monomial. + self.assertEqual(self.m13 + self.m2, self.m1) + + # Zero monomial + Zero monomial = Zero monomial + self.assertEqual(self.m1 + self.m1, self.m1) + + # Coefficient float. + self.assertEqual(self.m7 + self.m7, Monomial({1: 2, 7: 2}, -2*math.pi)) + + # Coefficient 0 so should equal the zero monomial. + self.assertEqual(self.m8, self.m1) + + # The constant term cannot be added to any monomial + # that has any variables. + self.assertRaises(ValueError, lambda x, y: x + y, self.m2, self.m9) + + # Any literal cannot be added to a Monomial. However, a monomial + # can be added to any int, float, Fraction, or Monomial. + + # So 2 + Monomial is raises TypeError but Monomial + 2 may work fine! + self.assertRaises(TypeError, lambda x, y: x + y, self.m9, self.m2) + + # Any constant added to a zero monomial produces + # a monomial. + self.assertEqual(self.m1 + self.m9, Monomial({}, 2)) + self.assertEqual(self.m1 + self.m12, Monomial({}, 0)) + + return + + def test_monomial_subtraction(self): + + # Monomials with different underlying variables or + # even different power of those variables must not be subtracted! + self.assertRaises(ValueError, lambda x, y: x - y, self.m1, self.m2) + self.assertRaises(ValueError, lambda x, y: x - y, self.m2, self.m3) + self.assertRaises(ValueError, lambda x, y: x - y, self.m2, self.m14) + + # Additive inverses of each other should produce the zero monomial. + self.assertEqual(self.m2 - self.m2, self.m1) + self.assertEqual(self.m2 - self.m2, Monomial({}, 0)) + + # Zero monomial - Zero monomial = Zero monomial + self.assertEqual(self.m1 - self.m1, self.m1) + + # Coefficient int. + self.assertEqual(self.m2 - self.m15, Monomial({1: 1}, -1)) + + # Coefficient float. + self.assertEqual(self.m16 - self.m7, Monomial({1: 2, 7: 2}, 2*math.pi)) + + + # The constant term cannot be added to any monomial + # that has any variables. + self.assertRaises(ValueError, lambda x, y: x - y, self.m2, self.m9) + + # Any literal cannot be added to a Monomial. However, a monomial + # can be added to any int, float, Fraction, or Monomial. + + # So 2 + Monomial is raises TypeError but Monomial + 2 may work fine! + self.assertRaises(TypeError, lambda x, y: x - y, self.m9, self.m2) + + # Any constant added to a zero monomial produces + # a monomial. + self.assertEqual(self.m1 - self.m9, Monomial({}, -2)) + self.assertEqual(self.m1 - self.m12, Monomial({}, 0)) + + return + + def test_monomial_multiplication(self): + + # Usual multiplication. + # The positive and negative powers of the same variable + # should cancel out. + self.assertEqual(self.m2 * self.m13, Monomial({1: 2}, -4)) + self.assertEqual(self.m2 * self.m17, Monomial({}, 2)) + + # A coefficient of zero should make the product zero. + # Zero monomial * any int, float, Fraction, or Monomial = Zero monomial + self.assertEqual(self.m8 * self.m5, self.m1) + self.assertEqual(self.m1 * self.m2, self.m1) + + # Test usual float multiplication. + self.assertEqual(self.m7 * self.m3, Monomial({1: 4, 2: -1, 7: 2}, -1.5*math.pi)) + + return + + def test_monomial_inverse(self): + + # The Zero monomial is not invertible. + self.assertRaises(ValueError, lambda x: x.inverse(), self.m1) + self.assertRaises(ValueError, lambda x: x.inverse(), self.m8) + self.assertRaises(ValueError, lambda x: x.inverse(), Monomial({},self.m12)) + + # Check some inverses. + self.assertEqual(self.m7.inverse(), Monomial({1: -2, 7: -2}, -1/math.pi)) + + # Doesn't matter if the coefficient is Fraction or float. + # Both should be treated as same. + self.assertEqual(self.m5.inverse(), Monomial({2: -1}, Fraction(3, 2))) + self.assertEqual(self.m5.inverse(), Monomial({2: -1}, 1.5)) + + # Should work fine without variables too! + self.assertTrue(self.m6.inverse(), Monomial({}, Fraction(-100, 227))) + self.assertEqual(self.m6.inverse(), Monomial({}, -1/2.27)) + return + + def test_monomial_division(self): + # Any monomial divided by the Zero Monomial should raise a ValueError. + self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), self.m2, self.m1) + self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), self.m2, self.m8) + self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), self.m2, self.m12) + + # Test some usual cases. + self.assertEqual(self.m7 / self.m3, Monomial({2: 1, 7: 2}, -2*math.pi/3)) + self.assertEqual(self.m14 / self.m13, Monomial({1: 1}) * Fraction(-3, 2)) + + return + + def test_monomial_substitution(self): + # Test with int. + self.assertAlmostEqual(self.m7.substitute(2), -16*math.pi, delta=1e-9) + # Test with float. + self.assertAlmostEqual(self.m7.substitute(1.5), (1.5 ** 4)* -math.pi, delta=1e-9) + # Test with Fraction. + self.assertAlmostEqual(self.m7.substitute(Fraction(-1, 2)), (Fraction(-1, 2) ** 4)*-math.pi, delta=1e-9) + # Test with a complete substitution map. + self.assertAlmostEqual(self.m7.substitute({1: 3, 7: 0}), (3 ** 2) * (0 ** 2) * -math.pi, delta=1e-9) + # Test with a more than complete substitution map. + self.assertAlmostEqual(self.m7.substitute({1: 3, 7: 0, 2: 2}), (3 ** 2) * (0 ** 2) * -math.pi, delta=1e-9) + + # Should raise a ValueError if not enough variables are supplied! + self.assertRaises(ValueError, lambda x, y: x.substitute(y), self.m7, {1: 3, 2: 2}) + self.assertRaises(ValueError, lambda x, y: x.substitute(y), self.m7, {2: 2}) + + # The zero monomial always gives zero upon substitution. + self.assertEqual(self.m8.substitute(2), 0) + self.assertEqual(self.m8.substitute({1231: 2, 1: 2}), 0) + + return + + def test_monomial_all_variables(self): + + # Any variable with zero power should not exist in the set + # of variables. + self.assertEqual(self.m5.all_variables(), {2}) + self.assertEqual(self.m6.all_variables(), set()) + + # The zero monomial should output empty set. + self.assertEqual(self.m8.all_variables(), set()) + + return + + def test_monomial_clone(self): + + # A monomial should produce its copy + # with same underlying variable dictionary + # and same coefficient. + self.assertEqual(self.m3, self.m3.clone()) + + # The zero monomial is identified and + # always clones to itself. + self.assertEqual(self.m1, self.m8.clone()) + self.assertEqual(self.m1, self.m1.clone()) + self.assertEqual(self.m8, self.m1.clone()) + self.assertEqual(self.m8, self.m8.clone()) + return + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/test_polynomial.py b/tests/test_polynomial.py new file mode 100644 index 000000000..4ba2ba6b7 --- /dev/null +++ b/tests/test_polynomial.py @@ -0,0 +1,175 @@ +from algorithms.maths.polynomial import ( + Polynomial, + Monomial +) +from fractions import Fraction +import math + + +import unittest + +class TestSuite(unittest.TestCase): + + def setUp(self): + self.p0 = Polynomial([ + Monomial({}) + ]) + self.p1 = Polynomial([ + Monomial({}), Monomial({}) + ]) + self.p2 = Polynomial([ + Monomial({1: 1}, 2) + ]) + self.p3 = Polynomial([ + Monomial({1: 1}, 2), + Monomial({1: 2, 2: -1}, 1.5) + ]) + self.p4 = Polynomial([ + Monomial({2: 1, 3: 0}, Fraction(2, 3)), + Monomial({1: -1, 3: 2}, math.pi), + Monomial({1: -1, 3: 2}, 1) + ]) + self.p5 = Polynomial([ + Monomial({150: 5, 170: 2, 10000:3}, 0), + Monomial({1: -1, 3: 2}, 1), + ]) + self.p6 = Polynomial([ + 2, + -3, + Fraction(1, 7), + 2**math.pi, + Monomial({2: 3, 3: 1}, 1.25) + ]) + self.p7 = Polynomial([ + Monomial({1: 1}, -2), + Monomial({1: 2, 2: -1}, -1.5) + ]) + + self.m1 = Monomial({1: 2, 2: 3}, -1) + + return + + def test_polynomial_addition(self): + + # The zero polynomials should add up to + # itselves only. + self.assertEqual(self.p0 + self.p1, self.p0) + self.assertEqual(self.p0 + self.p1, self.p1) + + # Additive inverses should add up to the + # zero polynomial. + self.assertEqual(self.p3 + self.p7, self.p0) + self.assertEqual(self.p3 + self.p7, self.p1) + + # Like terms should combine. + # The order of monomials should not matter. + self.assertEqual(self.p2 + self.p3, Polynomial([ + Monomial({1: 1}, 4), + Monomial({1: 2, 2: -1}, 1.5) + ])) + self.assertEqual(self.p2 + self.p3, Polynomial([ + Monomial({1: 2, 2: -1}, 1.5), + Monomial({1: 1}, 4), + ])) + + # Another typical computation. + self.assertEqual(self.p5 + self.p6, Polynomial([ + Monomial({}, 7.96783496993343), + Monomial({2: 3, 3: 1}, 1.25), + Monomial({1: -1, 3: 2}) + ])) + + return + + def test_polynomial_subtraction(self): + + self.assertEqual(self.p3 - self.p2, Polynomial([ + Monomial({1: 2, 2: -1}, 1.5) + ])) + + self.assertEqual(self.p3 - self.p3, Polynomial([])) + + self.assertEqual(self.p2 - self.p3, Polynomial([ + Monomial({1: 2, 2: -1}, -1.5) + ])) + + pass + + def test_polynomial_multiplication(self): + self.assertEqual(self.p0 * self.p2, Polynomial([])) + self.assertEqual(self.p1 * self.p2, Polynomial([])) + + self.assertEqual(self.p2 * self.p3, Polynomial([ + Monomial({1: 2}, 4), + Monomial({1: 3, 2: -1}, Fraction(3, 1)) + ])) + return + + def test_polynomial_division(self): + + # Should raise a ValueError if the divisor is not a monomial + # or a polynomial with only one term. + self.assertRaises(ValueError, lambda x, y: x / y, self.p5, self.p3) + self.assertRaises(ValueError, lambda x, y: x / y, self.p6, self.p4) + + self.assertEqual(self.p3 / self.p2, Polynomial([ + Monomial({}, 1), + Monomial({1: 1, 2: -1}, 0.75) + ])) + self.assertEqual(self.p7 / self.m1, Polynomial([ + Monomial({1: -1, 2: -3}, 2), + Monomial({1: 0, 2: -4}, 1.5) + ])) + self.assertEqual(self.p7 / self.m1, Polynomial([ + Monomial({1: -1, 2: -3}, 2), + Monomial({2: -4}, 1.5) + ])) + return + + def test_polynomial_variables(self): + # The zero polynomial has no variables. + + self.assertEqual(self.p0.variables(), set()) + self.assertEqual(self.p1.variables(), set()) + + # The total variables are the union of the variables + # from the monomials. + self.assertEqual(self.p4.variables(), {1, 2, 3}) + + # The monomials with coefficient 0 should be dropped. + self.assertEqual(self.p5.variables(), {1, 3}) + return + + def test_polynomial_subs(self): + # Anything substitued in the zero polynomial + # should evaluate to 0. + self.assertEqual(self.p1.subs(2), 0) + self.assertEqual(self.p0.subs(-101231), 0) + + # Should raise a ValueError if not enough variables are supplied. + self.assertRaises(ValueError, lambda x, y: x.subs(y), self.p4, {1: 3, 2: 2}) + self.assertRaises(ValueError, lambda x, y: x.subs(y), self.p4, {}) + + # Should work fine if a complete subsitution map is provided. + self.assertAlmostEqual(self.p4.subs({1: 1, 2: 1, 3: 1}), (1 + math.pi + Fraction(2, 3)), delta=1e-9) + # Should work fine if more than enough substitutions are provided. + self.assertAlmostEqual(self.p4.subs({1: 1, 2: 1, 3: 1, 4: 1}), (1 + math.pi + Fraction(2, 3)), delta=1e-9) + return + + def test_polynomial_clone(self): + + # The zero polynomial always clones to itself. + self.assertEqual(self.p0.clone(), self.p0) + self.assertEqual(self.p1.clone(), self.p0) + self.assertEqual(self.p0.clone(), self.p1) + self.assertEqual(self.p1.clone(), self.p1) + + # The polynomial should clone nicely. + self.assertEqual(self.p4.clone(), self.p4) + + # The monomial with a zero coefficient should be dropped + # in the clone. + self.assertEqual(self.p5.clone(), Polynomial([ + Monomial({1: -1, 3: 2}, 1) + ])) + return \ No newline at end of file From 162024fad3fcbad047ac26bed121dd6ce8da8d06 Mon Sep 17 00:00:00 2001 From: Aditya Bennur <46860321+TheCodeYoda@users.noreply.github.com> Date: Fri, 4 Dec 2020 20:40:04 +0530 Subject: [PATCH 245/302] Adding k_factor.py in dp folder in add_K_FactorofStrings branch (#743) * Adding k_factor.py in dp folder in add_K_FactorofStrings branch * Added tests for K_factor of strings * updated README by adding kfactor into dp section * updated __init__.py in dp folder Co-authored-by: Aditya --- README.md | 1 + algorithms/dp/__init__.py | 1 + algorithms/dp/k_factor.py | 68 +++++++++++++++++++++++++++++++++++++++ tests/test_dp.py | 29 ++++++++++++++++- 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 algorithms/dp/k_factor.py diff --git a/README.md b/README.md index e192204e2..c14e68468 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ If you want to uninstall algorithms, it is as simple as: - [word_break](algorithms/dp/word_break.py) - [fibonacci](algorithms/dp/fib.py) - [hosoya triangle](algorithms/dp/hosoya_triangle.py) + - [K-Factor_strings](algorithms/dp/k_factor.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) diff --git a/algorithms/dp/__init__.py b/algorithms/dp/__init__.py index c96a9b334..4492a9c9b 100644 --- a/algorithms/dp/__init__.py +++ b/algorithms/dp/__init__.py @@ -19,3 +19,4 @@ from .rod_cut import * from .word_break import * from .int_divide import * +from .k_factor import * diff --git a/algorithms/dp/k_factor.py b/algorithms/dp/k_factor.py new file mode 100644 index 000000000..2fd23d18b --- /dev/null +++ b/algorithms/dp/k_factor.py @@ -0,0 +1,68 @@ +'''The K factor of a string is defined as the number of times 'abba' appears as a substring. +Given two numbers N and k,​ find the number of strings of length N with 'K factor' = k. + +The algorithms is as follows: + +dp[n][k] will be a 4 element array, wherein each element can be the number of strings of length n and 'K factor' = k which belong to the criteria represented by that index: + + dp[n][k][0] can be the number of strings of length n and K-factor = k which end with substring 'a' + dp[n][k][1] can be the number of strings of length n and K-factor = k which end with substring 'ab' + dp[n][k][2] can be the number of strings of length n and K-factor = k which end with substring 'abb' + dp[n][k][3] can be the number of strings of length n and K-factor = k which end with anything other than the above substrings (anything other than 'a' 'ab' 'abb') + +Example inputs + +n=4 k=1 no of strings = 1 +n=7 k=1 no of strings = 70302 +n=10 k=2 no of strings = 74357 + +''' + +def find_k_factor(n,k): + dp=[[[0 for i in range(4)]for j in range((n-1)//3+2)]for k in range(n+1)] + if(3*k+1>n): + return 0 + #base cases + dp[1][0][0]=1; + dp[1][0][1]=0; + dp[1][0][2]=0; + dp[1][0][3]=25; + + for i in range(2,n+1): + for j in range((n-1)//3+2): + if(j==0): + #adding a at the end + dp[i][j][0]=dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][j][3] + + #adding b at the end + dp[i][j][1]=dp[i-1][j][0] + dp[i][j][2]=dp[i-1][j][1] + + #adding any other lowercase character + dp[i][j][3]=dp[i-1][j][0]*24+dp[i-1][j][1]*24+dp[i-1][j][2]*25+dp[i-1][j][3]*25 + + elif(3*j+1 Date: Sun, 17 Jan 2021 17:32:30 +0530 Subject: [PATCH 246/302] Create longest_sum_contigous_array.py --- .../arrays/longest_sum_contigous_array.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 algorithms/arrays/longest_sum_contigous_array.py diff --git a/algorithms/arrays/longest_sum_contigous_array.py b/algorithms/arrays/longest_sum_contigous_array.py new file mode 100644 index 000000000..40cd5a448 --- /dev/null +++ b/algorithms/arrays/longest_sum_contigous_array.py @@ -0,0 +1,64 @@ +""" +Find the sum of contiguous subarray within a one-dimensional array of numbers which has the largest sum. + +The idea of algorithm is to look for all positive contiguous segments of the array (max_ending_here is used for this). +And keep track of maximum sum contiguous segment among all positive segments (max_so_far is used for this). +Each time we get a positive sum compare it with max_so_far and update max_so_far if it is greater than max_so_far + +Example) +Let input array = [-2,-3,4,-1,-2,1,5,3] + +max_so_far = max_ending_here = 0 + +for i=0, a[0] = -2 +max_ending_here = max_ending_here + (-2) +Set max_ending_here = 0 because max_ending_here < 0 + +for i=1, a[1] = -3 +max_ending_here = max_ending_here + (-3) +Set max_ending_here = 0 because max_ending_here < 0 + +for i=2, a[2] = 4 +max_ending_here = max_ending_here + (4) +max_ending_here = 4 +max_so_far is updated to 4 because max_ending_here greater +than max_so_far which was 0 till now + +for i=3, a[3] = -1 +max_ending_here = max_ending_here + (-1) +max_ending_here = 3 + +for i=4, a[4] = -2 +max_ending_here = max_ending_here + (-2) +max_ending_here = 1 + +for i=5, a[5] = 1 +max_ending_here = max_ending_here + (1) +max_ending_here = 2 + +for i=6, a[6] = 5 +max_ending_here = max_ending_here + (5) +max_ending_here = 7 +max_so_far is updated to 7 because max_ending_here is +greater than max_so_far + +for i=7, a[7] = -3 +max_ending_here = max_ending_here + (-3) +max_ending_here = 4 + +4+(-1)+(-2)+1+5 = 7 +hence,maximum contiguous array sum is 7 +""" +def max_subarray_sum(a,size): + + max_so_far = 0 + max_ending_here = 0 + + for i in range(0, size): + max_ending_here = max_ending_here + a[i] + if max_ending_here < 0: + max_ending_here = 0 + elif (max_so_far < max_ending_here): + max_so_far = max_ending_here + + return max_so_far From 77cfed5c2a67cb81d3f3cf3650f190231d0b932e Mon Sep 17 00:00:00 2001 From: Divyanshmandhan-1 <70142854+Divyanshmandhan-1@users.noreply.github.com> Date: Mon, 18 Jan 2021 10:50:44 +0530 Subject: [PATCH 247/302] add ternary search --- algorithms/search/ternary_search.py | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 algorithms/search/ternary_search.py diff --git a/algorithms/search/ternary_search.py b/algorithms/search/ternary_search.py new file mode 100644 index 000000000..b7d36fb21 --- /dev/null +++ b/algorithms/search/ternary_search.py @@ -0,0 +1,37 @@ +""" +Ternary search is a divide and conquer algorithm that can be used to find an element in an array. +It is similar to binary search where we divide the array into two parts but in this algorithm, +we divide the given array into three parts and determine which has the key (searched element). +We can divide the array into three parts by taking mid1 and mid2. +Initially, l and r will be equal to 0 and n-1 respectively, where n is the length of the array. +mid1 = l + (r-l)/3 +mid2 = r – (r-l)/3 + +Note: Array needs to be sorted to perform ternary search on it. +T(N) = O(log3(N)) +log3 = log base 3 +""" +def ternary_search(l, r, key, arr): + while r >= l: + + mid1 = l + (r-l) // 3 + mid2 = r - (r-l) // 3 + + if key == arr[mid1]: + return mid1 + if key == mid2: + return mid2 + + if key < arr[mid1]: + # key lies between l and mid1 + r = mid1 - 1 + elif key > arr[mid2]: + # key lies between mid2 and r + l = mid2 + 1 + else: + # key lies between mid1 and mid2 + l = mid1 + 1 + r = mid2 - 1 + + # key not found + return -1 From 7a1e7250d248cb098db6b06e28df50564006f806 Mon Sep 17 00:00:00 2001 From: Divyanshmandhan-1 <70142854+Divyanshmandhan-1@users.noreply.github.com> Date: Mon, 18 Jan 2021 10:59:07 +0530 Subject: [PATCH 248/302] Delete longest_sum_contigous_array.py --- .../arrays/longest_sum_contigous_array.py | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 algorithms/arrays/longest_sum_contigous_array.py diff --git a/algorithms/arrays/longest_sum_contigous_array.py b/algorithms/arrays/longest_sum_contigous_array.py deleted file mode 100644 index 40cd5a448..000000000 --- a/algorithms/arrays/longest_sum_contigous_array.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Find the sum of contiguous subarray within a one-dimensional array of numbers which has the largest sum. - -The idea of algorithm is to look for all positive contiguous segments of the array (max_ending_here is used for this). -And keep track of maximum sum contiguous segment among all positive segments (max_so_far is used for this). -Each time we get a positive sum compare it with max_so_far and update max_so_far if it is greater than max_so_far - -Example) -Let input array = [-2,-3,4,-1,-2,1,5,3] - -max_so_far = max_ending_here = 0 - -for i=0, a[0] = -2 -max_ending_here = max_ending_here + (-2) -Set max_ending_here = 0 because max_ending_here < 0 - -for i=1, a[1] = -3 -max_ending_here = max_ending_here + (-3) -Set max_ending_here = 0 because max_ending_here < 0 - -for i=2, a[2] = 4 -max_ending_here = max_ending_here + (4) -max_ending_here = 4 -max_so_far is updated to 4 because max_ending_here greater -than max_so_far which was 0 till now - -for i=3, a[3] = -1 -max_ending_here = max_ending_here + (-1) -max_ending_here = 3 - -for i=4, a[4] = -2 -max_ending_here = max_ending_here + (-2) -max_ending_here = 1 - -for i=5, a[5] = 1 -max_ending_here = max_ending_here + (1) -max_ending_here = 2 - -for i=6, a[6] = 5 -max_ending_here = max_ending_here + (5) -max_ending_here = 7 -max_so_far is updated to 7 because max_ending_here is -greater than max_so_far - -for i=7, a[7] = -3 -max_ending_here = max_ending_here + (-3) -max_ending_here = 4 - -4+(-1)+(-2)+1+5 = 7 -hence,maximum contiguous array sum is 7 -""" -def max_subarray_sum(a,size): - - max_so_far = 0 - max_ending_here = 0 - - for i in range(0, size): - max_ending_here = max_ending_here + a[i] - if max_ending_here < 0: - max_ending_here = 0 - elif (max_so_far < max_ending_here): - max_so_far = max_ending_here - - return max_so_far From 2c04f10b6322754e3071b9bd0106f0785b3c64ce Mon Sep 17 00:00:00 2001 From: Vignesh Date: Sun, 24 Jan 2021 14:50:28 +0000 Subject: [PATCH 249/302] num_digits for negative values --- algorithms/maths/num_digits.py | 1 + tests/test_maths.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/algorithms/maths/num_digits.py b/algorithms/maths/num_digits.py index e8373d14b..93f0e20f3 100644 --- a/algorithms/maths/num_digits.py +++ b/algorithms/maths/num_digits.py @@ -5,6 +5,7 @@ import math def num_digits(n): + n=abs(n) if(n==0): return 1; return int(math.log10(n))+1 diff --git a/tests/test_maths.py b/tests/test_maths.py index 4ed370a1a..2b1e69315 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -461,6 +461,9 @@ def test_num_digits(self): self.assertEqual(2,num_digits(12)) self.assertEqual(5,num_digits(99999)) self.assertEqual(1,num_digits(8)) + self.assertEqual(1,num_digits(0)) + self.assertEqual(1,num_digits(-5)) + self.assertEqual(3,num_digits(-254)) if __name__ == "__main__": From fec7a5b09f696caaf042ea32358666239fa72a35 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Sun, 24 Jan 2021 14:52:39 +0000 Subject: [PATCH 250/302] .venv folder added in gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6ca05bc23..5152c3d1b 100755 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ __pycache__/ build/ pythonenv3.8/ .vscode/ +# Ignoring the virtual Environment when using GitHub Codespaces +.venv/ \ No newline at end of file From ef63e5329a02022d1f2a0dea27af9b367f6e2cf8 Mon Sep 17 00:00:00 2001 From: Divyanshmandhan-1 <70142854+Divyanshmandhan-1@users.noreply.github.com> Date: Thu, 28 Jan 2021 12:50:58 +0530 Subject: [PATCH 251/302] added test cases for ternary search --- algorithms/search/__init__.py | 1 + tests/test_search.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index 2586605e1..2226e4b5d 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -1,4 +1,5 @@ from .binary_search import * +from .ternary_search import * from .first_occurrence import * from .last_occurrence import * from .linear_search import * diff --git a/tests/test_search.py b/tests/test_search.py index 3f6c23f3e..d1ea8225d 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -1,5 +1,6 @@ from algorithms.search import ( binary_search, binary_search_recur, + ternary_search, first_occurrence, last_occurrence, linear_search, @@ -41,6 +42,15 @@ def test_binary_search(self): self.assertEqual(11, binary_search_recur(array, 0, 11, 6)) self.assertEqual(-1, binary_search_recur(array, 0, 11, 7)) self.assertEqual(-1, binary_search_recur(array, 0, 11, -1)) + + def test_ternary_search(self): + array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6] + self.assertEqual(10, ternary_search(0, 11, 5, array)) + self.assertEqual(3, ternary_search(0, 10, 3, array)) + self.assertEqual(-1, ternary_search(0, 10, 5, array)) + self.assertEqual(-1, ternary_search(0, 11, 7, array)) + self.assertEqual(-1, ternary_search(0, 11, -1, array)) + def test_last_occurrence(self): array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6, 6, 6] From 68be49ca496afe1f084bfc93e67247a27f0519fa Mon Sep 17 00:00:00 2001 From: Renstrom <48918700+Renstrom@users.noreply.github.com> Date: Sun, 7 Mar 2021 00:34:33 +0100 Subject: [PATCH 252/302] Add 1-sparse-recovery streaming algorithm (#762) * feat:(first draft for the misra gries algorithm) #1 * feat:(Added examples and changed to correct name) #1 * feat:(Added init file for testing) #2 * test:(Added tests for misras_gries function) #2 * feat:(add 1-sparse recovery algorithm) #7 * Add finalized 1-sparse-recovery algorithm * Renamed sparse function name to work with import * Tests added for 1-sparse-recovery function * Tests added for 1-sparse-recovery function Co-authored-by: callmeGoldenboy --- README.md | 2 + algorithms/streaming/__init__.py | 1 + algorithms/streaming/one_sparse_recovery.py | 61 +++++++++++++++++++++ tests/test_streaming.py | 15 +++++ 4 files changed, 79 insertions(+) create mode 100644 algorithms/streaming/__init__.py create mode 100644 algorithms/streaming/one_sparse_recovery.py create mode 100644 tests/test_streaming.py diff --git a/README.md b/README.md index c14e68468..ffe602b01 100644 --- a/README.md +++ b/README.md @@ -305,6 +305,8 @@ If you want to uninstall algorithms, it is as simple as: - [is_consecutive](algorithms/stack/is_consecutive.py) - [remove_min](algorithms/stack/remove_min.py) - [is_sorted](algorithms/stack/is_sorted.py) +- [streaming](algorithms/streaming) + - [1-sparse-recovery](algorithms/streaming/one_sparse_recovery.py) - [strings](algorithms/strings) - [fizzbuzz](algorithms/strings/fizzbuzz.py) - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) diff --git a/algorithms/streaming/__init__.py b/algorithms/streaming/__init__.py new file mode 100644 index 000000000..ba7a84ea8 --- /dev/null +++ b/algorithms/streaming/__init__.py @@ -0,0 +1 @@ +from .one_sparse_recovery import * \ No newline at end of file diff --git a/algorithms/streaming/one_sparse_recovery.py b/algorithms/streaming/one_sparse_recovery.py new file mode 100644 index 000000000..084a9f7b8 --- /dev/null +++ b/algorithms/streaming/one_sparse_recovery.py @@ -0,0 +1,61 @@ +""" Non-negative 1-sparse recovery problem. This algorithm assumes we have a non negative dynamic stream. +Given a stream of tuples, where each tuple contains a number and a sign (+/-), it check if the stream is 1-sparse, meaning if the elements +in the stream cancel eacheother out in such a way that ther is only a unique number at the end. + +Examples: +#1 +Input: [(4,'+'), (2,'+'),(2,'-'),(4,'+'),(3,'+'),(3,'-')], +Output: 4 +Comment: Since 2 and 3 gets removed. +#2 +Input: [(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+')] +Output: 2 +Comment: No other numbers present +#3 +Input: [(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(1,'+')] +Output: None +Comment: Not 1-sparse +""" + +def one_sparse(array): + sum_signs = 0 + bitsum = [0]*32 + sum_values = 0 + for val,sign in array: + if sign == "+": + sum_signs += 1 + sum_values += val + else: + sum_signs -= 1 + sum_values -= val + + _get_bit_sum(bitsum,val,sign) + + if sum_signs > 0 and _check_every_number_in_bitsum(bitsum,sum_signs): + return int(sum_values/sum_signs) + else: + return None + +#Helper function to check that every entry in the list is either 0 or the same as the +#sum of signs +def _check_every_number_in_bitsum(bitsum,sum_signs): + for val in bitsum: + if val != 0 and val != sum_signs : + return False + return True + +# Adds bit representation value to bitsum array +def _get_bit_sum(bitsum,val,sign): + i = 0 + if sign == "+": + while(val): + bitsum[i] += val & 1 + i +=1 + val >>=1 + else : + while(val): + bitsum[i] -= val & 1 + i +=1 + val >>=1 + + diff --git a/tests/test_streaming.py b/tests/test_streaming.py new file mode 100644 index 000000000..8662480e6 --- /dev/null +++ b/tests/test_streaming.py @@ -0,0 +1,15 @@ +from algorithms.streaming import ( + one_sparse +) +import unittest + +class TestOneSparse(unittest.TestCase): + def test_one_sparse_correct(self): + self.assertEqual(4,one_sparse([(4,'+'), (2,'+'),(2,'-'),(4,'+'),(3,'+'),(3,'-')])) + self.assertEqual(2,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+')])) + + + def test_one_sparse_incorrect(self): + self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(1,'+')])) #Two values remaining + self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'-'),(2,'-'),(2,'-'),(2,'-')])) # No values remaining + self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(4,'+'),(4,'+')])) # Bitsum sum of sign is inccorect \ No newline at end of file From 3074384b640291e68114584ffbc13b14ff311a07 Mon Sep 17 00:00:00 2001 From: Lazar Cerovic Date: Sun, 7 Mar 2021 00:40:28 +0100 Subject: [PATCH 253/302] Fix gcd (#760) * fix: add input argument checks and lcm/gcd can handle negative numbers * test: add new tests for gcd/lcm to test new fixes --- algorithms/maths/gcd.py | 14 +++++++++++++- tests/test_maths.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/algorithms/maths/gcd.py b/algorithms/maths/gcd.py index abc2814dd..35af7f118 100644 --- a/algorithms/maths/gcd.py +++ b/algorithms/maths/gcd.py @@ -1,7 +1,19 @@ def gcd(a, b): """Computes the greatest common divisor of integers a and b using Euclid's Algorithm. + gcd{𝑎,𝑏}=gcd{−𝑎,𝑏}=gcd{𝑎,−𝑏}=gcd{−𝑎,−𝑏} + See proof: https://proofwiki.org/wiki/GCD_for_Negative_Integers """ + a_int = isinstance(a, int) + b_int = isinstance(b, int) + a = abs(a) + b = abs(b) + if not(a_int or b_int): + raise ValueError("Input arguments are not integers") + + if (a == 0) or (b == 0) : + raise ValueError("One or more input arguments equals zero") + while b != 0: a, b = b, a % b return a @@ -9,7 +21,7 @@ def gcd(a, b): def lcm(a, b): """Computes the lowest common multiple of integers a and b.""" - return a * b / gcd(a, b) + return abs(a) * abs(b) / gcd(a, b) """ diff --git a/tests/test_maths.py b/tests/test_maths.py index 2b1e69315..95db71088 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -29,6 +29,7 @@ ) import unittest +import pytest class TestPower(unittest.TestCase): @@ -128,8 +129,37 @@ def test_gcd(self): self.assertEqual(4, gcd(8, 12)) self.assertEqual(1, gcd(13, 17)) + def test_gcd_non_integer_input(self): + with pytest.raises(ValueError, match=r"Input arguments are not integers"): + gcd(1.0, 5) + gcd(5, 6.7) + gcd(33.8649, 6.12312312) + + def test_gcd_zero_input(self): + with pytest.raises(ValueError, match=r"One or more input arguments equals zero"): + gcd(0, 12) + gcd(12, 0) + gcd(0, 0) + + def test_gcd_negative_input(self): + self.assertEqual(1, gcd(-13, -17)) + self.assertEqual(4, gcd(-8, 12)) + self.assertEqual(8, gcd(24, -16)) + def test_lcm(self): self.assertEqual(24, lcm(8, 12)) + self.assertEqual(5767, lcm(73, 79)) + + def test_lcm_negative_numbers(self): + self.assertEqual(24, lcm(-8, -12)) + self.assertEqual(5767, lcm(73, -79)) + self.assertEqual(1, lcm(-1, 1)) + + def test_lcm_zero_input(self): + with pytest.raises(ValueError, match=r"One or more input arguments equals zero"): + lcm(0, 12) + lcm(12, 0) + lcm(0, 0) def test_trailing_zero(self): self.assertEqual(1, trailing_zero(34)) @@ -140,6 +170,7 @@ def test_gcd_bit(self): self.assertEqual(1, gcd(13, 17)) + class TestGenerateStroboGrammatic(unittest.TestCase): """[summary] Test for the file generate_strobogrammatic.py From e685f8d3798ffeb0f4b91c4e40390748b8fc7c47 Mon Sep 17 00:00:00 2001 From: Natan Date: Mon, 8 Mar 2021 02:38:31 +0100 Subject: [PATCH 254/302] Add misra-gries streaming algorithm (#765) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:(first draft for the misra gries algorithm) #1 * feat:(Added examples and changed to correct name) #1 * feat:(Added init file for testing) #2 * test:(Added tests for misras_gries function) #2 * add misra-gries reference * add correct reference to misra_gries * add misra_gries import Co-authored-by: Anders Renström Co-authored-by: Keon --- README.md | 1 + algorithms/streaming/__init__.py | 3 +- algorithms/streaming/misra_gries.py | 49 +++++++++++++++++++++++++++++ tests/test_streaming.py | 19 +++++++++-- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 algorithms/streaming/misra_gries.py diff --git a/README.md b/README.md index ffe602b01..6280ff5af 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,7 @@ If you want to uninstall algorithms, it is as simple as: - [is_sorted](algorithms/stack/is_sorted.py) - [streaming](algorithms/streaming) - [1-sparse-recovery](algorithms/streaming/one_sparse_recovery.py) + - [misra-gries](algorithms/streaming/misra_gries.py) - [strings](algorithms/strings) - [fizzbuzz](algorithms/strings/fizzbuzz.py) - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) diff --git a/algorithms/streaming/__init__.py b/algorithms/streaming/__init__.py index ba7a84ea8..3e764d2c3 100644 --- a/algorithms/streaming/__init__.py +++ b/algorithms/streaming/__init__.py @@ -1 +1,2 @@ -from .one_sparse_recovery import * \ No newline at end of file +from .one_sparse_recovery import * +from .misra_gries import * diff --git a/algorithms/streaming/misra_gries.py b/algorithms/streaming/misra_gries.py new file mode 100644 index 000000000..31339094d --- /dev/null +++ b/algorithms/streaming/misra_gries.py @@ -0,0 +1,49 @@ + +""" +Implementation of the Misra-Gries algorithm. +Given a list of items and a value k, it returns the every item in the list that appears at least n/k times, where n is the length of the array +By default, k is set to 2, solving the majority problem. +For the majority problem, this algorithm only guarantees that if there is an element that appears more than n/2 times, it will be outputed. If there +is no such element, any arbitrary element is returned by the algorithm. Therefore, we need to iterate through again at the end. But since we have filtred +out the suspects, the memory complexity is significantly lower than it would be to create counter for every element in the list. + +For example: +Input misras_gries([1,4,4,4,5,4,4]) +Output {'4':5} +Input misras_gries([0,0,0,1,1,1,1]) +Output {'1':4} +Input misras_gries([0,0,0,0,1,1,1,2,2],3) +Output {'0':4,'1':3} +Input misras_gries([0,0,0,1,1,1] +Output None +""" +def misras_gries(array,k=2): + keys = {} + for i in range(len(array)): + val = str(array[i]) + if val in keys: + keys[val] = keys[val] + 1 + + elif len(keys) < k - 1: + keys[val] = 1 + + else: + for key in list(keys): + keys[key] = keys[key] - 1 + if keys[key] == 0: + del keys[key] + + suspects = keys.keys() + frequencies = {} + for suspect in suspects: + freq = _count_frequency(array,int(suspect)) + if freq >= len(array) / k: + frequencies[suspect] = freq + + return frequencies if len(frequencies) > 0 else None + + +def _count_frequency(array,element): + return array.count(element) + + diff --git a/tests/test_streaming.py b/tests/test_streaming.py index 8662480e6..701b5f4ce 100644 --- a/tests/test_streaming.py +++ b/tests/test_streaming.py @@ -1,7 +1,22 @@ +from algorithms.streaming.misra_gries import ( + misras_gries, +) from algorithms.streaming import ( one_sparse ) -import unittest +import unittest + + +class TestMisraGreis(unittest.TestCase): + def test_misra_correct(self): + self.assertEqual({'4':5},misras_gries([1,4,4,4,5,4,4])) + self.assertEqual({'1':4},misras_gries([0,0,0,1,1,1,1])) + self.assertEqual({'0':4,'1':3},misras_gries([0,0,0,0,1,1,1,2,2],3)) + + def test_misra_incorrect(self): + self.assertEqual(None,misras_gries([1,2,5,4,5,4,4,5,4,4,5])) + self.assertEqual(None,misras_gries([0,0,0,2,1,1,1])) + self.assertEqual(None,misras_gries([0,0,0,1,1,1])) class TestOneSparse(unittest.TestCase): def test_one_sparse_correct(self): @@ -12,4 +27,4 @@ def test_one_sparse_correct(self): def test_one_sparse_incorrect(self): self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(1,'+')])) #Two values remaining self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'-'),(2,'-'),(2,'-'),(2,'-')])) # No values remaining - self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(4,'+'),(4,'+')])) # Bitsum sum of sign is inccorect \ No newline at end of file + self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(4,'+'),(4,'+')])) # Bitsum sum of sign is inccorect From 6adcb360cd11108ae30dfca945e85fd3d35a869c Mon Sep 17 00:00:00 2001 From: Caroline Borg Date: Wed, 10 Mar 2021 11:24:36 +0100 Subject: [PATCH 255/302] Fix #756 (#771) Co-authored-by: Caroline Borg --- README.md | 1 + algorithms/strings/__init__.py | 1 + algorithms/strings/panagram.py | 36 +++++++++++++++ tests/test_strings.py | 81 +++++++++++++++++++++++++++++++++- 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 algorithms/strings/panagram.py diff --git a/README.md b/README.md index 6280ff5af..948fe6c4c 100644 --- a/README.md +++ b/README.md @@ -348,6 +348,7 @@ If you want to uninstall algorithms, it is as simple as: - [atbash_cipher](algorithms/strings/atbash_cipher.py) - [longest_palindromic_substring](algorithms/strings/longest_palindromic_substring.py) - [knuth_morris_pratt](algorithms/strings/knuth_morris_pratt.py) + - [panagram](algorithms/strings/panagram.py) - [tree](algorithms/tree) - [bst](algorithms/tree/bst) - [array_to_bst](algorithms/tree/bst/array_to_bst.py) diff --git a/algorithms/strings/__init__.py b/algorithms/strings/__init__.py index 37c83dfdd..496b1ebe5 100644 --- a/algorithms/strings/__init__.py +++ b/algorithms/strings/__init__.py @@ -38,3 +38,4 @@ from .atbash_cipher import * from .longest_palindromic_substring import * from .knuth_morris_pratt import * +from .panagram import * \ No newline at end of file diff --git a/algorithms/strings/panagram.py b/algorithms/strings/panagram.py new file mode 100644 index 000000000..d34965356 --- /dev/null +++ b/algorithms/strings/panagram.py @@ -0,0 +1,36 @@ +""" +Given a string, check whether it is a panagram or not. + +A panagram is a sentence that uses every letter at least once. + +The most famous example is: "he quick brown fox jumps over the lazy dog. + +Note: +A panagram in one language isn't necessarily a panagram in another. This +module assumes the english language. Hence, the Finnish panagram +'Törkylempijävongahdus' won't pass for a panagram despite being considered +a perfect panagram in its language. However, the Swedish panagram +'Yxmördaren Julia Blomqvist på fäktning i Schweiz' will pass despite +including letters not used in the english alphabet. This is because the +Swedish alphabet only extends the Latin one. +""" + +from string import ascii_lowercase + +def panagram(string): + """ + Returns whether the input string is an English panagram or not. + + Parameters: + string (str): A sentence in the form of a string. + + Returns: + A boolean with the result. + """ + letters = set(ascii_lowercase) + for c in string: + try: + letters.remove(c.lower()) + except: + pass + return len(letters) == 0 \ No newline at end of file diff --git a/tests/test_strings.py b/tests/test_strings.py index 5544086fa..519f12370 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -40,7 +40,8 @@ repeat_substring, atbash, longest_palindrome, - knuth_morris_pratt + knuth_morris_pratt, + panagram ) import unittest @@ -572,6 +573,84 @@ def test_knuth_morris_pratt(self): self.assertEqual([0, 4], knuth_morris_pratt("abcdabc", "abc")) self.assertEqual([], knuth_morris_pratt("aabcdaab", "aba")) +class TestPanagram(unittest.TestCase): + """[summary] + Test for the file panagram.py + + Arguments: + unittest {[type]} -- [description] + """ + + def test_empty_string(self): + # Arrange + string = "" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(False, res) + + def test_single_word_non_panagram(self): + # Arrange + string = "sentence" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(False, res) + + def test_fox_panagram_no_spaces(self): + # Arrange + string = "thequickbrownfoxjumpsoverthelazydog" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(True, res) + + def test_fox_panagram_mixed_case(self): + # Arrange + string = "theqUiCkbrOwnfOxjUMPSOVErThELAzYDog" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(True, res) + + def test_whitespace_punctuation(self): + # Arrange + string = "\n\t\r,.-_!?" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(False, res) + + def test_fox_panagram(self): + # Arrange + string = "the quick brown fox jumps over the lazy dog" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(True, res) + + def test_swedish_panagram(self): + # Arrange + string = "Yxmördaren Julia Blomqvist på fäktning i Schweiz" + + # Act + res = panagram(string) + + # Assert + self.assertEqual(True, res) + if __name__ == "__main__": unittest.main() From 8f6e5f0aa54fe82c00d677cda2f8bef345f001ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5ns=20Andersson?= <41705928+mansand1@users.noreply.github.com> Date: Fri, 12 Mar 2021 00:54:07 +0100 Subject: [PATCH 256/302] Add chinese remainder theorem (#759) * feat: Add basic ch. remainder theorem algorithm * feat: Add all n coprime check Co-authored-by: Lazar Cerovic * Add gcd function * Add list length > 0 check * doc: Improve function documentation * feat: add all divisors need to be > 1 * test: Add test cases for crt solver * fix: make check_coprime private * fix: Change to python3.7 type hints * refactor: Move ch. remainder theorem tests to test_maths * Add link in README * Remove unnecessary whitespace and add newline at end of file * docs: Fix README alphabetic order --- README.md | 1 + algorithms/maths/chinese_remainder_theorem.py | 46 +++++++++++++++++++ tests/test_maths.py | 33 ++++++++++++- 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 algorithms/maths/chinese_remainder_theorem.py diff --git a/README.md b/README.md index 948fe6c4c..8ccf3ba4c 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ If you want to uninstall algorithms, it is as simple as: - [is_anagram](algorithms/map/is_anagram.py) - [maths](algorithms/maths) - [base_conversion](algorithms/maths/base_conversion.py) + - [chinese_remainder_theorem](algorithms/maths/chinese_remainder_theorem.py) - [combination](algorithms/maths/combination.py) - [cosine_similarity](algorithms/maths/cosine_similarity.py) - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) diff --git a/algorithms/maths/chinese_remainder_theorem.py b/algorithms/maths/chinese_remainder_theorem.py new file mode 100644 index 000000000..91d9d1d9a --- /dev/null +++ b/algorithms/maths/chinese_remainder_theorem.py @@ -0,0 +1,46 @@ +from algorithms.maths.gcd import gcd +from typing import List + +def solve_chinese_remainder(num : List[int], rem : List[int]): + """ + Computes the smallest x that satisfies the chinese remainder theorem + for a system of equations. + The system of equations has the form: + x % num[0] = rem[0] + x % num[1] = rem[1] + ... + x % num[k - 1] = rem[k - 1] + Where k is the number of elements in num and rem, k > 0. + All numbers in num needs to be pariwise coprime otherwise an exception is raised + returns x: the smallest value for x that satisfies the system of equations + """ + if not len(num) == len(rem): + raise Exception("num and rem should have equal length") + if not len(num) > 0: + raise Exception("Lists num and rem need to contain at least one element") + for n in num: + if not n > 1: + raise Exception("All numbers in num needs to be > 1") + if not _check_coprime(num): + raise Exception("All pairs of numbers in num are not coprime") + k = len(num) + x = 1 + while True: + i = 0 + while i < k: + if x % num[i] != rem[i]: + break + i += 1 + if i == k: + return x + else: + x += 1 + +def _check_coprime(l : List[int]): + for i in range(len(l)): + for j in range(len(l)): + if i == j: + continue + if gcd(l[i], l[j]) != 1: + return False + return True diff --git a/tests/test_maths.py b/tests/test_maths.py index 95db71088..967cf64d9 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -25,7 +25,8 @@ alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, num_digits, alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, - diffie_hellman_key_exchange, krishnamurthy_number + diffie_hellman_key_exchange, krishnamurthy_number, + chinese_remainder_theorem, ) import unittest @@ -496,6 +497,36 @@ def test_num_digits(self): self.assertEqual(1,num_digits(-5)) self.assertEqual(3,num_digits(-254)) +class TestChineseRemainderSolver(unittest.TestCase): + def test_k_three(self): + # Example which should give the answer 143 + # which is the smallest possible x that + # solves the system of equations + num = [3, 7, 10] + rem = [2, 3, 3] + self.assertEqual(chinese_remainder_theorem.solve_chinese_remainder(num, rem), 143) + + def test_k_five(self): + # Example which should give the answer 3383 + # which is the smallest possible x that + # solves the system of equations + num = [3, 5, 7, 11, 26] + rem = [2, 3, 2, 6, 3] + self.assertEqual(chinese_remainder_theorem.solve_chinese_remainder(num, rem), 3383) + + def test_exception_non_coprime(self): + # There should be an exception when all + # numbers in num are not pairwise coprime + num = [3, 7, 10, 14] + rem = [2, 3, 3, 1] + with self.assertRaises(Exception): + chinese_remainder_theorem.solve_chinese_remainder(num, rem) + + def test_empty_lists(self): + num = [] + rem = [] + with self.assertRaises(Exception): + chinese_remainder_theorem.solve_chinese_remainder(num, rem) if __name__ == "__main__": unittest.main() From ab5de86b01fd7a8b166aadac92db056f8a048928 Mon Sep 17 00:00:00 2001 From: trangology Date: Tue, 23 Mar 2021 10:40:35 +0300 Subject: [PATCH 257/302] Fix failed test with negative search key & refactor code (#775) --- algorithms/search/interpolation_search.py | 30 ++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/algorithms/search/interpolation_search.py b/algorithms/search/interpolation_search.py index 0759180e3..9227e1f75 100644 --- a/algorithms/search/interpolation_search.py +++ b/algorithms/search/interpolation_search.py @@ -21,12 +21,14 @@ def interpolation_search(array: List[int], search_key: int) -> int: :returns: Index of search_key in array if found, else -1. - Example + Examples: - >>> interpolation_search([1, 10, 12, 15, 20, 41, 55], 20) - 4 + >>> interpolation_search([-25, -12, -1, 10, 12, 15, 20, 41, 55], -1) + 2 >>> interpolation_search([5, 10, 12, 14, 17, 20, 21], 55) -1 + >>> interpolation_search([5, 10, 12, 14, 17, 20, 21], -5) + -1 """ @@ -34,20 +36,26 @@ def interpolation_search(array: List[int], search_key: int) -> int: high = len(array) - 1 low = 0 - while low <= high and search_key in range(low, array[high] + 1): + while (low <= high) and (array[low] <= search_key <= array[high]): # calculate the search position pos = low + int(((search_key - array[low]) * (high - low) / (array[high] - array[low]))) - # if array[pos] equals the search_key then return pos as the index - if search_key == array[pos]: + # search_key is found + if array[pos] == search_key: return pos - # if the search_key is greater than array[pos] restart the search with the - # subarray greater than array[pos] - elif search_key > array[pos]: + + # if search_key is larger, search_key is in upper part + if array[pos] < search_key: low = pos + 1 - # in this case start the search with the subarray smaller than current array[pos] - elif search_key < array[pos]: + + # if search_key is smaller, search_key is in lower part + else: high = pos - 1 return -1 + + +if __name__ == "__main__": + import doctest + doctest.testmod() From 5995c053b41d0aeb922db908053fc6a1604d13cc Mon Sep 17 00:00:00 2001 From: Caroline Borg Date: Tue, 23 Mar 2021 11:26:24 +0100 Subject: [PATCH 258/302] Fix #768 (#770) --- README.md | 1 + algorithms/dp/__init__.py | 1 + algorithms/dp/planting_trees.py | 45 +++++++++++++++++++++++++++++++++ tests/test_dp.py | 27 +++++++++++++++++++- 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 algorithms/dp/planting_trees.py diff --git a/README.md b/README.md index 8ccf3ba4c..fdb9c0b7f 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ If you want to uninstall algorithms, it is as simple as: - [fibonacci](algorithms/dp/fib.py) - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - [K-Factor_strings](algorithms/dp/k_factor.py) + - [planting_trees](algorithms/dp/planting_trees.py) - [graph](algorithms/graph) - [check_bipartite](algorithms/graph/check_bipartite.py) - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) diff --git a/algorithms/dp/__init__.py b/algorithms/dp/__init__.py index 4492a9c9b..ac56eda74 100644 --- a/algorithms/dp/__init__.py +++ b/algorithms/dp/__init__.py @@ -20,3 +20,4 @@ from .word_break import * from .int_divide import * from .k_factor import * +from .planting_trees import * \ No newline at end of file diff --git a/algorithms/dp/planting_trees.py b/algorithms/dp/planting_trees.py new file mode 100644 index 000000000..c1efd4e64 --- /dev/null +++ b/algorithms/dp/planting_trees.py @@ -0,0 +1,45 @@ +""" +An even number of trees are left along one side of a country road. You've been assigned the job to +plant these trees at an even interval on both sides of the road. The length L and width W of the road +are variable, and a pair of trees must be planted at the beginning (at 0) and at the end (at L) of +the road. Only one tree can be moved at a time. The goal is to calculate the lowest amount of +distance that the trees have to be moved before they are all in a valid position. +""" + +from math import sqrt +import sys + +def planting_trees(trees, L, W): + """ + Returns the minimum distance that trees have to be moved before they are all in a valid state. + + Parameters: + tree (list): A sorted list of integers with all trees' position along the road. + L (int): An integer with the length of the road. + W (int): An integer with the width of the road. + + Returns: + A float number with the total distance trees have been moved. + """ + trees = [0] + trees + + n_pairs = int(len(trees)/2) + + space_between_pairs = L/(n_pairs-1) + + target_locations = [location*space_between_pairs for location in range(n_pairs)] + + cmatrix = [[0 for _ in range(n_pairs+1)] for _ in range(n_pairs+1)] + for ri in range(1, n_pairs+1): + cmatrix[ri][0] = cmatrix[ri-1][0] + sqrt(W + abs(trees[ri]-target_locations[ri-1])**2) + for li in range(1, n_pairs+1): + cmatrix[0][li] = cmatrix[0][li-1] + abs(trees[li]-target_locations[li-1]) + + for ri in range(1, n_pairs+1): + for li in range(1, n_pairs+1): + cmatrix[ri][li] = min( + cmatrix[ri-1][li] + sqrt(W + (trees[li + ri]-target_locations[ri-1])**2), + cmatrix[ri][li-1] + abs(trees[li + ri]-target_locations[li-1]) + ) + + return cmatrix[n_pairs][n_pairs] \ No newline at end of file diff --git a/tests/test_dp.py b/tests/test_dp.py index 177c5659f..300be3d85 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -13,7 +13,8 @@ longest_increasing_subsequence, longest_increasing_subsequence_optimized, longest_increasing_subsequence_optimized2, - int_divide,find_k_factor + int_divide,find_k_factor, + planting_trees ) @@ -182,6 +183,30 @@ def test_kfactor(self): k5=1 self.assertEqual(find_k_factor(n5,k5),71284044) +class TestPlantingTrees(unittest.TestCase): + def test_simple(self): + # arrange + trees = [0, 1, 10, 10] + L = 10 + W = 1 + + # act + res = planting_trees(trees, L, W) + + # assert + self.assertEqual(res, 2.414213562373095) + + def test_simple2(self): + # arrange + trees = [0, 3, 5, 5, 6, 9] + L = 10 + W = 1 + + # act + res = planting_trees(trees, L, W) + + # assert + self.assertEqual(res, 9.28538328578604) if __name__ == '__main__': unittest.main() From 339a0d276a2b216242c2828674e58e6043a4e708 Mon Sep 17 00:00:00 2001 From: Trenton South Date: Wed, 12 May 2021 16:03:55 -0500 Subject: [PATCH 259/302] fix_rotate.py (#778) * fix_rotate.py The way it was, you couldn't pass in a rotation higher than the length of the string doubled without getting a blank string in return. This way allows you to pass in any positive integer and get a result. Also, The last line of the description said that it took 2 strings and returned a boolean. This is not correct. The first line of the comment is correct. * Update rotate.py After submitting my last change, I realized it would have been better to not keep concatenating the string. * Updated Comments rotate.py --- algorithms/strings/rotate.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/algorithms/strings/rotate.py b/algorithms/strings/rotate.py index 7f713baf5..8be2bd4ba 100644 --- a/algorithms/strings/rotate.py +++ b/algorithms/strings/rotate.py @@ -1,18 +1,19 @@ """ Given a strings s and int k, return a string that rotates k times +k can be any positive integer. + For example, rotate("hello", 2) return "llohe" rotate("hello", 5) return "hello" rotate("hello", 6) return "elloh" rotate("hello", 7) return "llohe" +rotate("hello", 102) return "lohel" -accepts two strings -returns bool """ def rotate(s, k): - double_s = s + s + long_string = s * (k // len(s) + 2) if k <= len(s): - return double_s[k:k + len(s)] + return long_string[k:k + len(s)] else: - return double_s[k-len(s):k] + return long_string[k-len(s):k] From 0d3e4c12ed8ddf0f5a2f447afea06bfd3fa125e9 Mon Sep 17 00:00:00 2001 From: Clifton McCook <56374673+cliftonamccook@users.noreply.github.com> Date: Sun, 30 May 2021 18:57:25 -0500 Subject: [PATCH 260/302] Corrected spelling anf grammar errors in docstring for heap. (#783) --- algorithms/heap/binary_heap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/algorithms/heap/binary_heap.py b/algorithms/heap/binary_heap.py index 629be434a..927065b76 100644 --- a/algorithms/heap/binary_heap.py +++ b/algorithms/heap/binary_heap.py @@ -1,7 +1,7 @@ """ -Binary Heap. A min heap is a complete binary tree where each node is smaller -its childen. The root, therefore, is the minimum element in the tree. The min -heap use array to represent the data and operation. For example a min heap: +Binary Heap. A min heap is a complete binary tree where each node is smaller than +its children. The root, therefore, is the minimum element in the tree. The min +heap uses an array to represent the data and operation. For example a min heap: 4 / \ From 9b6b2523096dc2dfa8f6efe9016b1790ee4ecc47 Mon Sep 17 00:00:00 2001 From: Clifton McCook <56374673+cliftonamccook@users.noreply.github.com> Date: Sun, 30 May 2021 19:49:13 -0500 Subject: [PATCH 261/302] Updated binary_heap (#785) * Corrected spelling anf grammar errors in docstring for heap. * Fixed method signature for remove_min by removing unused parameter i. * Fixed grammar in min_child docstring. --- algorithms/heap/binary_heap.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/algorithms/heap/binary_heap.py b/algorithms/heap/binary_heap.py index 927065b76..ac7ff63bc 100644 --- a/algorithms/heap/binary_heap.py +++ b/algorithms/heap/binary_heap.py @@ -48,7 +48,7 @@ def perc_down(self,i): def min_child(self,i): pass @abstractmethod - def remove_min(self,i): + def remove_min(self): pass class BinaryHeap(AbstractHeap): def __init__(self): @@ -64,8 +64,8 @@ def perc_up(self, i): """ Method insert always start by inserting the element at the bottom. - it inserts rightmost spot so as to maintain the complete tree property - Then, it fix the tree by swapping the new element with its parent, + It inserts rightmost spot so as to maintain the complete tree property. + Then, it fixes the tree by swapping the new element with its parent, until it finds an appropriate spot for the element. It essentially perc_up the minimum element Complexity: O(logN) @@ -76,7 +76,7 @@ def insert(self, val): self.perc_up(self.currentSize) """ - Method min_child returns index of smaller 2 childs of its parent + Method min_child returns the index of smaller of 2 children of parent at index i """ def min_child(self, i): if 2 * i + 1 > self.currentSize: # No right child @@ -104,7 +104,7 @@ def perc_down(self, i): """ def remove_min(self): ret = self.heap[1] # the smallest value at beginning - self.heap[1] = self.heap[self.currentSize] # Repalce it by the last value + self.heap[1] = self.heap[self.currentSize] # Replace it by the last value self.currentSize = self.currentSize - 1 self.heap.pop() self.perc_down(1) From 5dde6a0f18af460642a363f57cfd431c1c4c8f66 Mon Sep 17 00:00:00 2001 From: Clifton McCook <56374673+cliftonamccook@users.noreply.github.com> Date: Sun, 30 May 2021 21:24:09 -0500 Subject: [PATCH 262/302] Fixed some invalid references and more spelling errors. (#786) * Corrected spelling anf grammar errors in docstring for heap. * Fixed method signature for remove_min by removing unused parameter i. * Fixed grammar in min_child docstring. * Fixed spelling error. * Fixed spelling errors in matrix_exponentiation.py * Removed trailing semicolons in matrix_inversion.py. TODO: Check for possible type error in line 61. * Fixed spelling error in base_conversion.py. * Fixed incorrect reference in min_height.py * Fixed incorrect reference in max_height.py --- algorithms/linkedlist/linkedlist.py | 2 +- algorithms/maths/base_conversion.py | 2 +- algorithms/matrix/matrix_exponentiation.py | 4 ++-- algorithms/matrix/matrix_inversion.py | 8 ++++---- algorithms/tree/max_height.py | 2 +- algorithms/tree/min_height.py | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/algorithms/linkedlist/linkedlist.py b/algorithms/linkedlist/linkedlist.py index 1b921c926..c7b8e0c4a 100644 --- a/algorithms/linkedlist/linkedlist.py +++ b/algorithms/linkedlist/linkedlist.py @@ -3,7 +3,7 @@ # in comparison, arrays require O(n) time to do the same thing. # Linked lists can continue to expand without having to specify # their size ahead of time (remember our lectures on Array sizing -# form the Array Sequence section of the course!) +# from the Array Sequence section of the course!) # Cons # To access an element in a linked list, you need to take O(k) time diff --git a/algorithms/maths/base_conversion.py b/algorithms/maths/base_conversion.py index cc3b62cbb..5d2a2214e 100644 --- a/algorithms/maths/base_conversion.py +++ b/algorithms/maths/base_conversion.py @@ -33,7 +33,7 @@ def int_to_base(n, base): def base_to_int(s, base): """ - Note : You can use int() built-in function instread of this. + Note : You can use int() built-in function instead of this. :type s: str :type base: int :rtype: int diff --git a/algorithms/matrix/matrix_exponentiation.py b/algorithms/matrix/matrix_exponentiation.py index f842bc2fd..f9673ce4a 100644 --- a/algorithms/matrix/matrix_exponentiation.py +++ b/algorithms/matrix/matrix_exponentiation.py @@ -16,7 +16,7 @@ def multiply(matA: list, matB: list) -> list: def identity(n: int) -> list: """ Returns the Identity matrix of size n x n - Time Complecity: O(n^2) + Time Complexity: O(n^2) """ I = [[0 for i in range(n)] for j in range(n)] @@ -29,7 +29,7 @@ def matrix_exponentiation(mat: list, n: int) -> list: """ Calculates mat^n by repeated squaring Time Complexity: O(d^3 log(n)) - d: dimesion of the square matrix mat + d: dimension of the square matrix mat n: power the matrix is raised to """ if n == 0: diff --git a/algorithms/matrix/matrix_inversion.py b/algorithms/matrix/matrix_inversion.py index 7dfb093ff..8d8102d41 100644 --- a/algorithms/matrix/matrix_inversion.py +++ b/algorithms/matrix/matrix_inversion.py @@ -28,16 +28,16 @@ def invert_matrix(m): # Error conditions if not array_is_matrix(m): print("Invalid matrix: array is not a matrix") - return [[-1]]; + return [[-1]] elif len(m) != len(m[0]): print("Invalid matrix: matrix is not square") - return [[-2]]; + return [[-2]] elif len(m) < 2: print("Invalid matrix: matrix is too small") - return [[-3]]; + return [[-3]] elif get_determinant(m) == 0: print("Invalid matrix: matrix is square, but singular (determinant = 0)") - return [[-4]]; + return [[-4]] # Calculation elif len(m) == 2: diff --git a/algorithms/tree/max_height.py b/algorithms/tree/max_height.py index ee9c80cde..c732ac079 100644 --- a/algorithms/tree/max_height.py +++ b/algorithms/tree/max_height.py @@ -12,7 +12,7 @@ # iterative -from tree.tree import TreeNode +from tree import TreeNode def max_height(root): diff --git a/algorithms/tree/min_height.py b/algorithms/tree/min_height.py index a33517dec..7913e2965 100644 --- a/algorithms/tree/min_height.py +++ b/algorithms/tree/min_height.py @@ -1,4 +1,4 @@ -from tree.tree import TreeNode +from tree import TreeNode def min_depth(self, root): From 779bc2fb4515cdff8e927cdbadeb2fdff7f426bf Mon Sep 17 00:00:00 2001 From: Karan Gadani <52932210+karangadani@users.noreply.github.com> Date: Mon, 28 Jun 2021 21:08:04 +0530 Subject: [PATCH 263/302] LPS Algorithm is Added Fixed Issues #746 (#788) * Longest Palindromic Subsequence Algorithm is Added * test case added * Renamed --- README.md | 1 + .../map/longest_palindromic_subsequence.py | 22 +++++++++++++++++++ tests/test_map.py | 15 ++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 algorithms/map/longest_palindromic_subsequence.py diff --git a/README.md b/README.md index fdb9c0b7f..105c82505 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ If you want to uninstall algorithms, it is as simple as: - [hashtable](algorithms/map/hashtable.py) - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [longest_palindromic_subsequence](algorithms/map/longest_palindromic_subsequence.py) - [randomized_set](algorithms/map/randomized_set.py) - [valid_sudoku](algorithms/map/valid_sudoku.py) - [word_pattern](algorithms/map/word_pattern.py) diff --git a/algorithms/map/longest_palindromic_subsequence.py b/algorithms/map/longest_palindromic_subsequence.py new file mode 100644 index 000000000..93cc6dd8b --- /dev/null +++ b/algorithms/map/longest_palindromic_subsequence.py @@ -0,0 +1,22 @@ +def longest_palindromic_subsequence(str): + n = len(str) + + # Create a table to store results of subproblems + L = [[0 for x in range(n)] for x in range(n)] + + for i in range(n): + L[i][i] = 1 + + + for sub_string_length in range(2, n + 1): + for i in range(n-sub_string_length + 1): + j = i + sub_string_length-1 + if str[i] == str[j] and sub_string_length == 2: + L[i][j] = 2 + elif str[i] == str[j]: + L[i][j] = L[i + 1][j-1] + 2 + else: + L[i][j] = max(L[i][j-1], L[i + 1][j]); + + return L[0][n-1] + diff --git a/tests/test_map.py b/tests/test_map.py index aaff34a98..2df7ca0fa 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -3,7 +3,8 @@ Node, SeparateChainingHashTable, word_pattern, is_isomorphic, - is_anagram + is_anagram, + longest_palindromic_subsequence, ) import unittest @@ -164,6 +165,18 @@ def test_is_isomorphic(self): self.assertFalse(is_isomorphic("foo", "bar")) self.assertTrue(is_isomorphic("paper", "title")) +class TestLongestPalindromicSubsequence(unittest.TestCase): + def test_longest_palindromic_subsequence_is_correct(self): + self.assertEqual(7,longest_palindromic_subsequence('BBABCBCAB')) + self.assertEqual(4,longest_palindromic_subsequence('abbaeae')) + self.assertEqual(8,longest_palindromic_subsequence('babbbababaa')) + self.assertEqual(6,longest_palindromic_subsequence('daccandeeja')) + + def test_longest_palindromic_subsequence_is_incorrect(self): + self.assertEqual(4,longest_palindromic_subsequence('BBABCBCAB')) + self.assertEqual(5,longest_palindromic_subsequence('abbaeae')) + self.assertEqual(2,longest_palindromic_subsequence('babbbababaa')) + self.assertEqual(1,longest_palindromic_subsequence('daccandeeja')) class TestIsAnagram(unittest.TestCase): def test_is_anagram(self): From d54f4a5628c2ccf8b7b358017c74377defd2773e Mon Sep 17 00:00:00 2001 From: kq58 <1772617802@qq.com> Date: Tue, 10 Aug 2021 12:30:14 +0800 Subject: [PATCH 264/302] this could be an implementation of lps. (#796) * Update longest_palindromic_subsequence.py * Update __init__.py * Update test_map.py --- algorithms/map/__init__.py | 1 + .../map/longest_palindromic_subsequence.py | 49 +++++++++++-------- tests/test_map.py | 14 +++--- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/algorithms/map/__init__.py b/algorithms/map/__init__.py index 233348d37..931c0e776 100644 --- a/algorithms/map/__init__.py +++ b/algorithms/map/__init__.py @@ -3,3 +3,4 @@ from .word_pattern import * from .is_isomorphic import * from .is_anagram import * +from .longest_palindromic_subsequence import * diff --git a/algorithms/map/longest_palindromic_subsequence.py b/algorithms/map/longest_palindromic_subsequence.py index 93cc6dd8b..767e78f44 100644 --- a/algorithms/map/longest_palindromic_subsequence.py +++ b/algorithms/map/longest_palindromic_subsequence.py @@ -1,22 +1,29 @@ -def longest_palindromic_subsequence(str): - n = len(str) - - # Create a table to store results of subproblems - L = [[0 for x in range(n)] for x in range(n)] - - for i in range(n): - L[i][i] = 1 - - - for sub_string_length in range(2, n + 1): - for i in range(n-sub_string_length + 1): - j = i + sub_string_length-1 - if str[i] == str[j] and sub_string_length == 2: - L[i][j] = 2 - elif str[i] == str[j]: - L[i][j] = L[i + 1][j-1] + 2 - else: - L[i][j] = max(L[i][j-1], L[i + 1][j]); - - return L[0][n-1] +def longest_palindromic_subsequence(s): + + k = len(s) + olist = [0] * k # 申请长度为n的列表,并初始化 + nList = [0] * k # 同上 + logestSubStr = "" + logestLen = 0 + for j in range(0, k): + for i in range(0, j + 1): + if j - i <= 1: + if s[i] == s[j]: + nList[i] = 1 # 当 j 时,第 i 个子串为回文子串 + len_t = j - i + 1 + if logestLen < len_t: # 判断长度 + logestSubStr = s[i:j + 1] + logestLen = len_t + else: + if s[i] == s[j] and olist[i+1]: # 当j-i>1时,判断s[i]是否等于s[j],并判断当j-1时,第i+1个子串是否为回文子串 + nList[i] = 1 # 当 j 时,第 i 个子串为回文子串 + len_t = j - i + 1 + if logestLen < len_t: + logestSubStr = s[i:j + 1] + logestLen = len_t + olist = nList # 覆盖旧的列表 + nList = [0] * k # 新的列表清空 + # ~ from icecream import ic + # ~ ic(s, logestSubStr) + return logestLen#, logestSubStr diff --git a/tests/test_map.py b/tests/test_map.py index 2df7ca0fa..c8164881b 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -167,16 +167,16 @@ def test_is_isomorphic(self): class TestLongestPalindromicSubsequence(unittest.TestCase): def test_longest_palindromic_subsequence_is_correct(self): - self.assertEqual(7,longest_palindromic_subsequence('BBABCBCAB')) + self.assertEqual(3,longest_palindromic_subsequence('BBABCBCAB')) self.assertEqual(4,longest_palindromic_subsequence('abbaeae')) - self.assertEqual(8,longest_palindromic_subsequence('babbbababaa')) - self.assertEqual(6,longest_palindromic_subsequence('daccandeeja')) + self.assertEqual(7,longest_palindromic_subsequence('babbbababaa')) + self.assertEqual(4,longest_palindromic_subsequence('daccandeeja')) def test_longest_palindromic_subsequence_is_incorrect(self): - self.assertEqual(4,longest_palindromic_subsequence('BBABCBCAB')) - self.assertEqual(5,longest_palindromic_subsequence('abbaeae')) - self.assertEqual(2,longest_palindromic_subsequence('babbbababaa')) - self.assertEqual(1,longest_palindromic_subsequence('daccandeeja')) + self.assertNotEqual(4,longest_palindromic_subsequence('BBABCBCAB')) + self.assertNotEqual(5,longest_palindromic_subsequence('abbaeae')) + self.assertNotEqual(2,longest_palindromic_subsequence('babbbababaa')) + self.assertNotEqual(1,longest_palindromic_subsequence('daccandeeja')) class TestIsAnagram(unittest.TestCase): def test_is_anagram(self): From 6e7e1f26350c2538a0ed6384e6a3332797fe9bc0 Mon Sep 17 00:00:00 2001 From: Banuteja <67595337+PAPPALA-BANUTEJA-NAIDU@users.noreply.github.com> Date: Thu, 2 Sep 2021 07:35:17 +0530 Subject: [PATCH 265/302] Add another implementation (#802) * Add tests for rotate.py * Add another implementation --- algorithms/strings/rotate.py | 4 ++++ tests/test_strings.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/algorithms/strings/rotate.py b/algorithms/strings/rotate.py index 8be2bd4ba..5bfcd1971 100644 --- a/algorithms/strings/rotate.py +++ b/algorithms/strings/rotate.py @@ -17,3 +17,7 @@ def rotate(s, k): return long_string[k:k + len(s)] else: return long_string[k-len(s):k] + +def rotate_alt(string, k): + k = k % len(string) + return string[k:] + string[:k] diff --git a/tests/test_strings.py b/tests/test_strings.py index 519f12370..1158630b1 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -225,6 +225,12 @@ def test_rotate(self): self.assertEqual("hello", rotate("hello", 5)) self.assertEqual("elloh", rotate("hello", 6)) self.assertEqual("llohe", rotate("hello", 7)) + + def test_rotate_alt(self): + self.assertEqual("llohe", rotate_alt("hello", 2)) + self.assertEqual("hello", rotate_alt("hello", 5)) + self.assertEqual("elloh", rotate_alt("hello", 6)) + self.assertEqual("llohe", rotate_alt("hello", 7)) class TestLicenseNumber(unittest.TestCase): From a9e57d459557f0bcd2bad1e8fac302ab72d34fe8 Mon Sep 17 00:00:00 2001 From: Banuteja <67595337+PAPPALA-BANUTEJA-NAIDU@users.noreply.github.com> Date: Fri, 3 Sep 2021 05:31:28 +0530 Subject: [PATCH 266/302] Palindrome using deque (#803) * Add method using deque * updated tests for is_palindrome.py deque --- algorithms/strings/is_palindrome.py | 18 ++++++++++++++++++ tests/test_strings.py | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/algorithms/strings/is_palindrome.py b/algorithms/strings/is_palindrome.py index 40f404a37..11a9e3063 100644 --- a/algorithms/strings/is_palindrome.py +++ b/algorithms/strings/is_palindrome.py @@ -11,6 +11,7 @@ we define empty string as valid palindrome. """ from string import ascii_letters +from collections import deque def is_palindrome(s): @@ -85,3 +86,20 @@ def is_palindrome_stack(s): if s[i] != stack.pop(): return False return True + +# Variation 4 (using deque) +def is_palindrome_deque(s): + s = remove_punctuation(s) + deq = deque() + for char in s: + deq.appendleft(char) + + equal = True + + while len(deq) > 1 and equal: + first = deq.pop() + last = deq.popleft() + if first != last : + equal = False + + return equal diff --git a/tests/test_strings.py b/tests/test_strings.py index 1158630b1..2b1110866 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -8,7 +8,7 @@ group_anagrams, int_to_roman, is_palindrome, is_palindrome_reverse, - is_palindrome_two_pointer, is_palindrome_stack, + is_palindrome_two_pointer, is_palindrome_stack, is_palindrome_deque, is_rotated, is_rotated_v1, license_number, make_sentence, @@ -195,6 +195,11 @@ def test_is_palindrome_stack(self): self.assertTrue(is_palindrome_stack("Otto")) self.assertFalse(is_palindrome_stack("house")) + def test_is_palindrome_deque(self): + # 'Otto' is a old german name. + self.assertTrue(is_palindrome_deque("Otto")) + self.assertFalse(is_palindrome_deque("house")) + class TestIsRotated(unittest.TestCase): """[summary] From 34871c5be9a109c3b614832b75041a0ed707c53c Mon Sep 17 00:00:00 2001 From: Mo Yi Date: Mon, 8 Nov 2021 23:45:43 +0800 Subject: [PATCH 267/302] typo (#811) --- algorithms/tree/segment_tree/segment_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/tree/segment_tree/segment_tree.py b/algorithms/tree/segment_tree/segment_tree.py index 2bf51966f..94aeba5dd 100644 --- a/algorithms/tree/segment_tree/segment_tree.py +++ b/algorithms/tree/segment_tree/segment_tree.py @@ -8,7 +8,7 @@ def __init__(self,arr,function): self.segment = [0 for x in range(3*len(arr)+3)] self.arr = arr self.fn = function - self.maketree(0,0,len(arr)-1) + self.make_tree(0,0,len(arr)-1) def make_tree(self,i,l,r): if l==r: From 1dcf31c4f9845fd3c2b5b385ff5c6682220376ee Mon Sep 17 00:00:00 2001 From: Nate Wilkinson Date: Wed, 17 Nov 2021 08:54:46 -0700 Subject: [PATCH 268/302] Bugfix: Add missing import for rotate_alt test Adds a missing import for the test of rotate_alt --- tests/test_strings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_strings.py b/tests/test_strings.py index 2b1110866..907a3897f 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -35,7 +35,7 @@ text_justification, min_distance, longest_common_prefix_v1, longest_common_prefix_v2, longest_common_prefix_v3, - rotate, + rotate, rotate_alt, first_unique_char, repeat_substring, atbash, From 02d451da3d3e51e017cfff47c4f28f5b757ba02c Mon Sep 17 00:00:00 2001 From: Milad Khoshdel Date: Thu, 18 Nov 2021 11:49:17 +0330 Subject: [PATCH 269/302] Increase performance of Function 3 Times Faster Response --- algorithms/arrays/limit.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py index c6100da1c..e0cc30586 100644 --- a/algorithms/arrays/limit.py +++ b/algorithms/arrays/limit.py @@ -14,7 +14,4 @@ # tl:dr -- array slicing by value def limit(arr, min_lim=None, max_lim=None): - min_check = lambda val: True if min_lim is None else (min_lim <= val) - max_check = lambda val: True if max_lim is None else (val <= max_lim) - - return [val for val in arr if min_check(val) and max_check(val)] + return list(filter(lambda x: (min_lim <= x <= max_lim), arr)) From 23d4e85a506eaeaff315e855be12f8dbe47a7ec3 Mon Sep 17 00:00:00 2001 From: KimAYoung <57066971+Kim-AYoung@users.noreply.github.com> Date: Thu, 16 Dec 2021 22:02:43 +0900 Subject: [PATCH 270/302] Added exchange sort (#816) * add_exchange_sort --- README.md | 1 + algorithms/sort/__init__.py | 1 + algorithms/sort/exchange_sort.py | 11 +++++++++++ tests/test_sort.py | 4 ++++ 4 files changed, 17 insertions(+) create mode 100644 algorithms/sort/exchange_sort.py diff --git a/README.md b/README.md index 105c82505..d8fc9c46f 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,7 @@ If you want to uninstall algorithms, it is as simple as: - [comb_sort](algorithms/sort/comb_sort.py) - [counting_sort](algorithms/sort/counting_sort.py) - [cycle_sort](algorithms/sort/cycle_sort.py) + - [exchange_sort](algorithms/sort/exchange_sort.py) - [gnome_sort](algorithms/sort/gnome_sort.py) - [heap_sort](algorithms/sort/heap_sort.py) - [insertion_sort](algorithms/sort/insertion_sort.py) diff --git a/algorithms/sort/__init__.py b/algorithms/sort/__init__.py index b948dba48..fb186c024 100644 --- a/algorithms/sort/__init__.py +++ b/algorithms/sort/__init__.py @@ -4,6 +4,7 @@ from .comb_sort import * from .counting_sort import * from .cycle_sort import * +from .exchange_sort import * from .heap_sort import * from .insertion_sort import * from .merge_sort import * diff --git a/algorithms/sort/exchange_sort.py b/algorithms/sort/exchange_sort.py new file mode 100644 index 000000000..c2d2e7923 --- /dev/null +++ b/algorithms/sort/exchange_sort.py @@ -0,0 +1,11 @@ +def exchange_sort(arr): + """ + Reference : https://en.wikipedia.org/wiki/Sorting_algorithm#Exchange_sort + Complexity : O(n^2) + """ + arr_len = len(arr) + for i in range(arr_len-1): + for j in range(i+1, arr_len): + if(arr[i] > arr[j]): + arr[i], arr[j] = arr[j], arr[i] + return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index e3fb498b7..2c23ab8a5 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -5,6 +5,7 @@ comb_sort, counting_sort, cycle_sort, + exchange_sort, max_heap_sort, min_heap_sort, insertion_sort, merge_sort, @@ -55,6 +56,9 @@ def test_counting_sort(self): def test_cycle_sort(self): self.assertTrue(is_sorted(cycle_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + def test_exchange_sort(self): + self.assertTrue(is_sorted(exchange_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + def test_heap_sort(self): self.assertTrue(is_sorted(max_heap_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) From 65cc8551d86d7e065069d165dd8bf9baf10345a0 Mon Sep 17 00:00:00 2001 From: Mithun Date: Sun, 9 Jan 2022 11:19:33 +0400 Subject: [PATCH 271/302] minor updates (#822) --- algorithms/stack/stack.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/algorithms/stack/stack.py b/algorithms/stack/stack.py index 216c26492..d1a148e36 100644 --- a/algorithms/stack/stack.py +++ b/algorithms/stack/stack.py @@ -8,10 +8,8 @@ It needs no parameters and returns the item. The stack is modified. peek() returns the top item from the stack but does not remove it. It needs no parameters. The stack is not modified. -isEmpty() tests to see whether the stack is empty. +is_empty() tests to see whether the stack is empty. It needs no parameters and returns a boolean value. -size() returns the number of items on the stack. - It needs no parameters and returns an integer. """ from abc import ABCMeta, abstractmethod class AbstractStack(metaclass=ABCMeta): @@ -72,7 +70,7 @@ def push(self, value): def pop(self): if self.is_empty(): - raise IndexError("stack is empty") + raise IndexError("Stack is empty") value = self._array[self._top] self._top -= 1 return value @@ -80,7 +78,7 @@ def pop(self): def peek(self): """returns the current top element of the stack.""" if self.is_empty(): - raise IndexError("stack is empty") + raise IndexError("Stack is empty") return self._array[self._top] def _expand(self): From 6fb00bc3a9aa9ba99ffb2ab16835c5f1bb67a438 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 15 Feb 2022 10:05:17 +0530 Subject: [PATCH 272/302] Create python-app.yml --- .github/workflows/python-app.yml | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/python-app.yml diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 000000000..8c262bdd2 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,36 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python application + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest From c12305ca4ba67d06b6448fb9be17f592a93e56e3 Mon Sep 17 00:00:00 2001 From: Aalekh Patel Date: Tue, 15 Feb 2022 23:52:29 -0600 Subject: [PATCH 273/302] Update pytest command. (#831) Invoke pytest as a python module rather than a standalone executable. --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 8c262bdd2..1eb737ecd 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -33,4 +33,4 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | - pytest + python -m pytest From a3109408486ad22ddb563e6cd2f5b0921233543c Mon Sep 17 00:00:00 2001 From: Aalekh Patel Date: Wed, 16 Feb 2022 00:00:43 -0600 Subject: [PATCH 274/302] Bug fix: Add None checks for the boundary values. (#832) Its bugging me that CI workflow is failing because of a test for this function. This bug fix should bring green ticks back again. ;) --- algorithms/arrays/limit.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/algorithms/arrays/limit.py b/algorithms/arrays/limit.py index e0cc30586..57f6561f8 100644 --- a/algorithms/arrays/limit.py +++ b/algorithms/arrays/limit.py @@ -14,4 +14,12 @@ # tl:dr -- array slicing by value def limit(arr, min_lim=None, max_lim=None): + if len(arr) == 0: + return arr + + if min_lim is None: + min_lim = min(arr) + if max_lim is None: + max_lim = max(arr) + return list(filter(lambda x: (min_lim <= x <= max_lim), arr)) From 6c54611213d0b6a0615f503dceaa962302f5f071 Mon Sep 17 00:00:00 2001 From: Per Arn Date: Thu, 24 Feb 2022 11:13:32 +0100 Subject: [PATCH 275/302] Added testing for the fizzbuzz algorithm. (#833) --- tests/test_strings.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/tests/test_strings.py b/tests/test_strings.py index 907a3897f..893498156 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -41,7 +41,8 @@ atbash, longest_palindrome, knuth_morris_pratt, - panagram + panagram, + fizzbuzz ) import unittest @@ -662,6 +663,33 @@ def test_swedish_panagram(self): # Assert self.assertEqual(True, res) - +class TestFizzbuzz(unittest.TestCase): + """[summary] + Tests for the fizzbuzz method in file fizzbuzz.py + """ + + def test_fizzbuzz(self): + # Testing that n < 0 returns a Value Error + self.assertRaises(ValueError, fizzbuzz.fizzbuzz, -2) + + # Testing that a string returns a Type Error. + self.assertRaises(TypeError, fizzbuzz.fizzbuzz, "hello") + + # Testing a base case, n = 3 + result = fizzbuzz.fizzbuzz(3) + expected = [1, 2, "Fizz"] + self.assertEqual(result, expected) + + # Testing a base case, n = 5 + result = fizzbuzz.fizzbuzz(5) + expected = [1, 2, "Fizz", 4, "Buzz"] + self.assertEqual(result, expected) + + # Testing a base case, n = 15 i.e. mod 3 and 5 + result = fizzbuzz.fizzbuzz(15) + expected = [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, + "Fizz", 13, 14, "FizzBuzz"] + self.assertEqual(result, expected) + if __name__ == "__main__": unittest.main() From 617d2d5ad654b451aafadf90304358a0358c309e Mon Sep 17 00:00:00 2001 From: James Wiens Date: Thu, 24 Feb 2022 23:18:58 -0800 Subject: [PATCH 276/302] Fix broken link in wiki (fenwick tree) (#790) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d8fc9c46f..2234b67fa 100644 --- a/README.md +++ b/README.md @@ -370,7 +370,6 @@ If you want to uninstall algorithms, it is as simple as: - [count_left_node](algorithms/tree/bst/count_left_node.py) - [num_empty](algorithms/tree/bst/num_empty.py) - [height](algorithms/tree/bst/height.py) - - [fenwick_tree](algorithms/tree/fenwick_tree] - [fenwick_tree](algorithms/tree/fenwick_tree/fenwick_tree.py) - [red_black_tree](algorithms/tree/red_black_tree) - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) From 87eae9a25751a13d4ef48860fffa4df0998356eb Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 2 Mar 2022 09:28:54 +0530 Subject: [PATCH 277/302] Fix flake8 issues (#836) --- algorithms/tree/is_balanced.py | 5 +- docs/source/conf.py | 14 +-- setup.py | 2 - tests/test_array.py | 90 ++++++++++------ tests/test_automata.py | 22 ++-- tests/test_backtrack.py | 106 +++++++++++-------- tests/test_bfs.py | 27 +++-- tests/test_bit.py | 28 +++-- tests/test_compression.py | 25 +++-- tests/test_dfs.py | 58 +++++++---- tests/test_dp.py | 62 +++++------ tests/test_graph.py | 149 +++++++++++++------------- tests/test_heap.py | 6 +- tests/test_iterative_segment_tree.py | 24 +++-- tests/test_map.py | 29 +++--- tests/test_maths.py | 44 ++++---- tests/test_matrix.py | 55 ++++++---- tests/test_ml.py | 33 +++--- tests/test_monomial.py | 68 +++++++----- tests/test_queues.py | 9 +- tests/test_search.py | 3 +- tests/test_set.py | 4 +- tests/test_sort.py | 50 +++++---- tests/test_stack.py | 3 + tests/test_streaming.py | 37 ++++--- tests/test_strings.py | 150 ++++++++++++++++----------- tests/test_tree.py | 16 ++- tests/test_unix.py | 14 ++- 28 files changed, 665 insertions(+), 468 deletions(-) diff --git a/algorithms/tree/is_balanced.py b/algorithms/tree/is_balanced.py index 004daaa37..3910e1b7e 100644 --- a/algorithms/tree/is_balanced.py +++ b/algorithms/tree/is_balanced.py @@ -15,7 +15,7 @@ def __get_depth(root): """ if root is None: return 0 - left = __get_depth(root.left) + left = __get_depth(root.left) right = __get_depth(root.right) if abs(left-right) > 1 or -1 in [left, right]: return -1 @@ -28,7 +28,8 @@ def __get_depth(root): # """ # left = max_height(root.left) # right = max_height(root.right) -# return abs(left-right) <= 1 and is_balanced(root.left) and is_balanced(root.right) +# return abs(left-right) <= 1 and is_balanced(root.left) and +# is_balanced(root.right) # def max_height(root): # if root is None: diff --git a/docs/source/conf.py b/docs/source/conf.py index b6c0c8320..768277d1b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -32,13 +32,13 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages'] + 'sphinx.ext.doctest', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/setup.py b/setup.py index 56099a55c..c5bb20141 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,4 @@ -import os import io -import re from setuptools import find_packages, setup diff --git a/tests/test_array.py b/tests/test_array.py index c02b2754e..83a4840d5 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -3,7 +3,8 @@ flatten_iter, flatten, garage, josephus, - longest_non_repeat_v1, longest_non_repeat_v2, get_longest_non_repeat_v1, get_longest_non_repeat_v2, + longest_non_repeat_v1, longest_non_repeat_v2, + get_longest_non_repeat_v1, get_longest_non_repeat_v2, Interval, merge_intervals, missing_ranges, move_zeros, @@ -51,12 +52,14 @@ def test_delete_nth_naive(self): [1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), [1, 1, 3, 3, 7, 2, 2, 2]) self.assertListEqual(delete_nth_naive( - [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=3), + [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], + n=3), [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]) self.assertListEqual(delete_nth_naive([], n=5), []) self.assertListEqual(delete_nth_naive( - [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=0), + [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], + n=0), []) def test_delete_nth(self): @@ -65,11 +68,13 @@ def test_delete_nth(self): [20, 37, 21]) self.assertListEqual(delete_nth([1, 1, 3, 3, 7, 2, 2, 2, 2], n=3), [1, 1, 3, 3, 7, 2, 2, 2]) - self.assertListEqual(delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=3), + self.assertListEqual(delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, + 5, 3, 1], n=3), [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]) self.assertListEqual(delete_nth([], n=5), []) - self.assertListEqual(delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], n=0), + self.assertListEqual(delete_nth([1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, + 5, 3, 1], n=0), []) @@ -169,9 +174,8 @@ def test_longest_non_repeat_v2(self): string = "asjrgapa" self.assertEqual(longest_non_repeat_v2(string), 6) - + def test_get_longest_non_repeat_v1(self): - string = "abcabcbb" self.assertEqual(get_longest_non_repeat_v1(string), (3, 'abc')) @@ -188,7 +192,6 @@ def test_get_longest_non_repeat_v1(self): self.assertEqual(get_longest_non_repeat_v1(string), (6, 'sjrgap')) def test_get_longest_non_repeat_v2(self): - string = "abcabcbb" self.assertEqual(get_longest_non_repeat_v2(string), (3, 'abc')) @@ -209,9 +212,12 @@ class TestMaxOnesIndex(unittest.TestCase): def test_max_ones_index(self): - self.assertEqual(9, max_ones_index([1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1])) - self.assertEqual(3, max_ones_index([1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1])) - self.assertEqual(-1, max_ones_index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])) + self.assertEqual(9, max_ones_index([1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, + 1, 1])) + self.assertEqual(3, max_ones_index([1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, + 1, 1])) + self.assertEqual(-1, max_ones_index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1])) class TestMergeInterval(unittest.TestCase): @@ -255,7 +261,8 @@ def test_move_zeros(self): self.assertListEqual(move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"]), [False, 1, 1, 2, 1, 3, "a", 0, 0]) - self.assertListEqual(move_zeros([0, 34, 'rahul', [], None, 0, True, 0]), + self.assertListEqual(move_zeros([0, 34, 'rahul', [], None, 0, + True, 0]), [34, 'rahul', [], None, True, 0, 0, 0]) @@ -297,31 +304,31 @@ class TestRotateArray(unittest.TestCase): def test_rotate_v1(self): self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=3), - [5, 6, 7, 1, 2, 3, 4]) + [5, 6, 7, 1, 2, 3, 4]) self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=1), - [7, 1, 2, 3, 4, 5, 6]) + [7, 1, 2, 3, 4, 5, 6]) self.assertListEqual(rotate_v1([1, 2, 3, 4, 5, 6, 7], k=7), - [1, 2, 3, 4, 5, 6, 7]) + [1, 2, 3, 4, 5, 6, 7]) self.assertListEqual(rotate_v1([1, 2], k=111), [2, 1]) def test_rotate_v2(self): self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=3), - [5, 6, 7, 1, 2, 3, 4]) + [5, 6, 7, 1, 2, 3, 4]) self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=1), - [7, 1, 2, 3, 4, 5, 6]) + [7, 1, 2, 3, 4, 5, 6]) self.assertListEqual(rotate_v2([1, 2, 3, 4, 5, 6, 7], k=7), - [1, 2, 3, 4, 5, 6, 7]) + [1, 2, 3, 4, 5, 6, 7]) self.assertListEqual(rotate_v2([1, 2], k=111), [2, 1]) def test_rotate_v3(self): self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=3), - [5, 6, 7, 1, 2, 3, 4]) + [5, 6, 7, 1, 2, 3, 4]) self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=1), - [7, 1, 2, 3, 4, 5, 6]) + [7, 1, 2, 3, 4, 5, 6]) self.assertListEqual(rotate_v3([1, 2, 3, 4, 5, 6, 7], k=7), - [1, 2, 3, 4, 5, 6, 7]) + [1, 2, 3, 4, 5, 6, 7]) self.assertListEqual(rotate_v3([1, 2], k=111), [2, 1]) @@ -363,14 +370,16 @@ class TestTrimmean(unittest.TestCase): def test_trimmean(self): self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 20), 5.5) - self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 20), 6.0) + self.assertEqual(trimmean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 20), + 6.0) class TestTop1(unittest.TestCase): def test_top_1(self): - self.assertListEqual(top_1([1 , 1, 2, 2, 3]), [1, 2]) - self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), [23]) + self.assertListEqual(top_1([1, 1, 2, 2, 3]), [1, 2]) + self.assertListEqual(top_1([1, 2, 3, 324, 234, 23, 23, 1, 23, 23]), + [23]) class TestLimit(unittest.TestCase): @@ -385,21 +394,34 @@ class TestNSum(unittest.TestCase): def test_n_sum(self): self.assertEqual(n_sum(2, [-3, 5, 2, 3, 8, -9], 6), []) # noqa: E501 - self.assertEqual(n_sum(3, [-5, -4, -3, -2, -1, 0, 1, 2, 3], 0), sorted([[-5,2,3],[-2,0,2],[-4,1,3],[-3,1,2],[-1,0,1],[-2,-1,3],[-3,0,3]])) # noqa: E501 - self.assertEqual(n_sum(3, [-1,0,1,2,-1,-4], 0), sorted([[-1,-1,2],[-1,0,1]])) # noqa: E501 - self.assertEqual(n_sum(4, [1, 0, -1, 0, -2, 2], 0), sorted([[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]])) # noqa: E501 + self.assertEqual(n_sum(3, [-5, -4, -3, -2, -1, 0, 1, 2, 3], 0), + sorted([[-5, 2, 3], [-2, 0, 2], [-4, 1, 3], + [-3, 1, 2], [-1, 0, 1], [-2, -1, 3], + [-3, 0, 3]])) # noqa: E501 + self.assertEqual(n_sum(3, [-1, 0, 1, 2, -1, -4], 0), + sorted([[-1, -1, 2], [-1, 0, 1]])) # noqa: E501 + self.assertEqual(n_sum(4, [1, 0, -1, 0, -2, 2], 0), + sorted([[-2, -1, 1, 2], [-2, 0, 0, 2], + [-1, 0, 0, 1]])) # noqa: E501 self.assertEqual(n_sum(4, [7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 6, 4, -3, -2], 10), sorted([[-6, 2, 7, 7], [-6, 3, 6, 7], [-6, 4, 5, 7], [-6, 4, 6, 6], [-5, 1, 7, 7], [-5, 2, 6, 7], [-5, 3, 5, 7], [-5, 3, 6, 6], [-5, 4, 4, 7], [-5, 4, 5, 6], [-4, 0, 7, 7], [-4, 1, 6, 7], [-4, 2, 5, 7], [-4, 2, 6, 6], [-4, 3, 4, 7], [-4, 3, 5, 6], [-4, 4, 4, 6], [-3, -1, 7, 7], [-3, 0, 6, 7], [-3, 1, 5, 7], [-3, 1, 6, 6], [-3, 2, 4, 7], [-3, 2, 5, 6], [-3, 3, 4, 6], [-3, 4, 4, 5], [-2, -2, 7, 7], [-2, -1, 6, 7], [-2, 0, 5, 7], [-2, 0, 6, 6], [-2, 1, 4, 7], [-2, 1, 5, 6], [-2, 2, 3, 7], [-2, 2, 4, 6], [-2, 3, 4, 5], [-1, 0, 4, 7], [-1, 0, 5, 6], [-1, 1, 3, 7], [-1, 1, 4, 6], [-1, 2, 3, 6], [-1, 2, 4, 5], [-1, 3, 4, 4], [0, 1, 2, 7], [0, 1, 3, 6], [0, 1, 4, 5], [0, 2, 3, 5], [0, 2, 4, 4], [1, 2, 3, 4]])) # noqa: E501 - self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], 0, # noqa: E501 + self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], + [-9, 5]], 0, # noqa: E501 sum_closure=lambda a, b: a[0] + b[0]), # noqa: E501 [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]]) # noqa: E501 - self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], [0, 3], # noqa: E501 - sum_closure=lambda a, b: [a[0] + b[0], a[1] + b[1]], # noqa: E501 - same_closure=lambda a, b: a[0] == b[0] and a[1] == b[1]), # noqa: E501 + self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], + [-9, 5]], [0, 3], # noqa: E501 + sum_closure=lambda a, b: [a[0] + b[0], + a[1] + b[1]], # noqa: E501 + same_closure=lambda a, b: a[0] == b[0] + and a[1] == b[1]), # noqa: E501 [[[-3, 0], [3, 3]], [[-2, 1], [2, 2]]]) # noqa: E501 - self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]], -5, # noqa: E501 - sum_closure=lambda a, b: [a[0] + b[1], a[1] + b[0]], # noqa: E501 - compare_closure=lambda a, b: -1 if a[0] < b else 1 if a[0] > b else 0), # noqa: E501 + self.assertEqual(n_sum(2, [[-3, 0], [-2, 1], [2, 2], [3, 3], + [8, 4], [-9, 5]], -5, # noqa: E501 + sum_closure=lambda a, b: [a[0] + b[1], + a[1] + b[0]], # noqa: E501 + compare_closure=lambda a, b: -1 if a[0] < b + else 1 if a[0] > b else 0), # noqa: E501 [[[-9, 5], [8, 4]]]) # noqa: E501 diff --git a/tests/test_automata.py b/tests/test_automata.py index 201c3d41b..dbd766a3f 100644 --- a/tests/test_automata.py +++ b/tests/test_automata.py @@ -6,43 +6,43 @@ class TestDFA(unittest.TestCase): def test_DFA(self): - transitions = { 'a': {'1': 'a', '0': 'b'}, 'b': {'1': 'b', '0': 'a'} } - final=['a'] + final = ['a'] start = 'a' - + self.assertEqual(False, DFA(transitions, start, final, "000111100")) self.assertEqual(True, DFA(transitions, start, final, "111000011")) - + transitions1 = { '0': {'0': '1', '1': '0'}, '1': {'0': '2', '1': '0'}, '2': {'0': '2', '1': '3'}, '3': {'0': '3', '1': '3'} - } - + } + final1 = ['0', '1', '2'] start1 = '0' - + self.assertEqual(False, DFA(transitions1, start1, final1, "0001111")) self.assertEqual(True, DFA(transitions1, start1, final1, "01010101")) - + transitions2 = { '0': {'a': '0', 'b': '1'}, '1': {'a': '0', 'b': '2'}, '2': {'a': '3', 'b': '2'}, '3': {'a': '3', 'b': '3'} } - - final2=['3'] + + final2 = ['3'] start2 = '0' self.assertEqual(False, DFA(transitions2, start2, final2, "aaabbb")) self.assertEqual(True, DFA(transitions2, start2, final2, "baabba")) - + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py index 682a89b04..4e9b9f612 100644 --- a/tests/test_backtrack.py +++ b/tests/test_backtrack.py @@ -1,6 +1,5 @@ from algorithms.backtrack import ( add_operators, - permute, permute_iter, anagram, array_sum_combinations, @@ -82,7 +81,8 @@ def test_array_sum_combinations(self): [1, 3, 3], [1, 4, 2], [2, 2, 3], [2, 2, 3], [2, 3, 2], [2, 3, 2], [3, 2, 2], [3, 2, 2]] answer.sort() - self.assertListEqual(sorted(array_sum_combinations(A, B, C, target)), answer) + self.assertListEqual(sorted(array_sum_combinations(A, B, C, target)), + answer) def test_unique_array_sum_combinations(self): A = [1, 2, 3, 3] @@ -92,7 +92,9 @@ def test_unique_array_sum_combinations(self): answer = [(2, 3, 2), (3, 2, 2), (1, 2, 4), (1, 4, 2), (2, 2, 3), (1, 3, 3)] answer.sort() - self.assertListEqual(sorted(unique_array_sum_combinations(A, B, C, target)), answer) + self.assertListEqual(sorted(unique_array_sum_combinations(A, B, C, + target)), + answer) class TestCombinationSum(unittest.TestCase): @@ -135,7 +137,7 @@ def test_get_factors(self): [4, 8] ] self.assertEqual(sorted(get_factors(target1)), sorted(answer1)) - + target2 = 12 answer2 = [ [2, 6], @@ -145,7 +147,7 @@ def test_get_factors(self): self.assertEqual(sorted(get_factors(target2)), sorted(answer2)) self.assertEqual(sorted(get_factors(1)), []) self.assertEqual(sorted(get_factors(37)), []) - + def test_recursive_get_factors(self): target1 = 32 answer1 = [ @@ -156,15 +158,17 @@ def test_recursive_get_factors(self): [2, 4, 4], [4, 8] ] - self.assertEqual(sorted(recursive_get_factors(target1)), sorted(answer1)) - + self.assertEqual(sorted(recursive_get_factors(target1)), + sorted(answer1)) + target2 = 12 answer2 = [ [2, 6], [2, 2, 3], [3, 4] ] - self.assertEqual(sorted(recursive_get_factors(target2)), sorted(answer2)) + self.assertEqual(sorted(recursive_get_factors(target2)), + sorted(answer2)) self.assertEqual(sorted(recursive_get_factors(1)), []) self.assertEqual(sorted(recursive_get_factors(37)), []) @@ -221,15 +225,18 @@ class TestGenerateAbbreviations(unittest.TestCase): def test_generate_abbreviations(self): word1 = "word" answer1 = ['word', 'wor1', 'wo1d', 'wo2', 'w1rd', 'w1r1', 'w2d', 'w3', - '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4'] - self.assertEqual(sorted(generate_abbreviations(word1)), sorted(answer1)) + '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4'] + self.assertEqual(sorted(generate_abbreviations(word1)), + sorted(answer1)) word2 = "hello" answer2 = ['hello', 'hell1', 'hel1o', 'hel2', 'he1lo', 'he1l1', 'he2o', - 'he3', 'h1llo', 'h1ll1', 'h1l1o', 'h1l2', 'h2lo', 'h2l1', 'h3o', 'h4', - '1ello', '1ell1', '1el1o', '1el2', '1e1lo', '1e1l1', '1e2o', '1e3', - '2llo', '2ll1', '2l1o', '2l2', '3lo', '3l1', '4o', '5'] - self.assertEqual(sorted(generate_abbreviations(word2)), sorted(answer2)) + 'he3', 'h1llo', 'h1ll1', 'h1l1o', 'h1l2', 'h2lo', 'h2l1', + 'h3o', 'h4', '1ello', '1ell1', '1el1o', '1el2', '1e1lo', + '1e1l1', '1e2o', '1e3', '2llo', '2ll1', '2l1o', '2l2', + '3lo', '3l1', '4o', '5'] + self.assertEqual(sorted(generate_abbreviations(word2)), + sorted(answer2)) class TestPatternMatch(unittest.TestCase): @@ -251,9 +258,11 @@ class TestGenerateParenthesis(unittest.TestCase): def test_generate_parenthesis(self): self.assertEqual(generate_parenthesis_v1(2), ['()()', '(())']) - self.assertEqual(generate_parenthesis_v1(3), ['()()()', '()(())', '(())()', '(()())', '((()))']) + self.assertEqual(generate_parenthesis_v1(3), ['()()()', '()(())', + '(())()', '(()())', '((()))']) self.assertEqual(generate_parenthesis_v2(2), ['(())', '()()']) - self.assertEqual(generate_parenthesis_v2(3), ['((()))', '(()())', '(())()', '()(())', '()()()']) + self.assertEqual(generate_parenthesis_v2(3), ['((()))', '(()())', + '(())()', '()(())', '()()()']) class TestLetterCombinations(unittest.TestCase): @@ -277,13 +286,17 @@ def test_palindromic_substrings(self): string2 = "abcba" answer2 = [['abcba'], ['a', 'bcb', 'a'], ['a', 'b', 'c', 'b', 'a']] - self.assertEqual(sorted(palindromic_substrings(string2)), sorted(answer2)) + self.assertEqual(sorted(palindromic_substrings(string2)), + sorted(answer2)) string3 = "abcccba" - answer3 = [['abcccba'], ['a', 'bcccb', 'a'], ['a', 'b', 'ccc', 'b', 'a'], - ['a', 'b', 'cc', 'c', 'b', 'a'], ['a', 'b', 'c', 'cc', 'b', 'a'], - ['a', 'b', 'c', 'c', 'c', 'b', 'a']] - self.assertEqual(sorted(palindromic_substrings(string3)), sorted(answer3)) + answer3 = [['abcccba'], ['a', 'bcccb', 'a'], + ['a', 'b', 'ccc', 'b', 'a'], + ['a', 'b', 'cc', 'c', 'b', 'a'], + ['a', 'b', 'c', 'cc', 'b', 'a'], + ['a', 'b', 'c', 'c', 'c', 'b', 'a']] + self.assertEqual(sorted(palindromic_substrings(string3)), + sorted(answer3)) class TestPermuteUnique(unittest.TestCase): @@ -294,12 +307,14 @@ def test_permute_unique(self): self.assertEqual(sorted(permute_unique(nums1)), sorted(answer1)) nums2 = [1, 2, 1, 3] - answer2 = [[3, 1, 2, 1], [1, 3, 2, 1], [1, 2, 3, 1], [1, 2, 1, 3], [3, 2, 1, 1], - [2, 3, 1, 1], [2, 1, 3, 1], [2, 1, 1, 3], [3, 1, 1, 2], [1, 3, 1, 2], [1, 1, 3, 2], [1, 1, 2, 3]] + answer2 = [[3, 1, 2, 1], [1, 3, 2, 1], [1, 2, 3, 1], [1, 2, 1, 3], + [3, 2, 1, 1], [2, 3, 1, 1], [2, 1, 3, 1], [2, 1, 1, 3], + [3, 1, 1, 2], [1, 3, 1, 2], [1, 1, 3, 2], [1, 1, 2, 3]] self.assertEqual(sorted(permute_unique(nums2)), sorted(answer2)) nums3 = [1, 2, 3] - answer3 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]] + answer3 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], + [1, 3, 2], [1, 2, 3]] self.assertEqual(sorted(permute_unique(nums3)), sorted(answer3)) @@ -307,28 +322,32 @@ class TestPermute(unittest.TestCase): def test_permute(self): nums1 = [1, 2, 3, 4] - answer1 = [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1], [1, 3, 2, 4], - [3, 1, 2, 4], [3, 2, 1, 4], [3, 2, 4, 1], [1, 3, 4, 2], [3, 1, 4, 2], - [3, 4, 1, 2], [3, 4, 2, 1], [1, 2, 4, 3], [2, 1, 4, 3], [2, 4, 1, 3], - [2, 4, 3, 1], [1, 4, 2, 3], [4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], - [1, 4, 3, 2], [4, 1, 3, 2], [4, 3, 1, 2], [4, 3, 2, 1]] + answer1 = [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1], + [1, 3, 2, 4], [3, 1, 2, 4], [3, 2, 1, 4], [3, 2, 4, 1], + [1, 3, 4, 2], [3, 1, 4, 2], [3, 4, 1, 2], [3, 4, 2, 1], + [1, 2, 4, 3], [2, 1, 4, 3], [2, 4, 1, 3], [2, 4, 3, 1], + [1, 4, 2, 3], [4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], + [1, 4, 3, 2], [4, 1, 3, 2], [4, 3, 1, 2], [4, 3, 2, 1]] self.assertEqual(sorted(permute(nums1)), sorted(answer1)) nums2 = [1, 2, 3] - answer2 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]] + answer2 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], + [1, 3, 2], [1, 2, 3]] self.assertEqual(sorted(permute(nums2)), sorted(answer2)) def test_permute_recursive(self): nums1 = [1, 2, 3, 4] - answer1 = [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1], [1, 3, 2, 4], - [3, 1, 2, 4], [3, 2, 1, 4], [3, 2, 4, 1], [1, 3, 4, 2], [3, 1, 4, 2], - [3, 4, 1, 2], [3, 4, 2, 1], [1, 2, 4, 3], [2, 1, 4, 3], [2, 4, 1, 3], - [2, 4, 3, 1], [1, 4, 2, 3], [4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], - [1, 4, 3, 2], [4, 1, 3, 2], [4, 3, 1, 2], [4, 3, 2, 1]] + answer1 = [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1], + [1, 3, 2, 4], [3, 1, 2, 4], [3, 2, 1, 4], [3, 2, 4, 1], + [1, 3, 4, 2], [3, 1, 4, 2], [3, 4, 1, 2], [3, 4, 2, 1], + [1, 2, 4, 3], [2, 1, 4, 3], [2, 4, 1, 3], [2, 4, 3, 1], + [1, 4, 2, 3], [4, 1, 2, 3], [4, 2, 1, 3], [4, 2, 3, 1], + [1, 4, 3, 2], [4, 1, 3, 2], [4, 3, 1, 2], [4, 3, 2, 1]] self.assertEqual(sorted(permute_recursive(nums1)), sorted(answer1)) nums2 = [1, 2, 3] - answer2 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]] + answer2 = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], + [1, 3, 2], [1, 2, 3]] self.assertEqual(sorted(permute_recursive(nums2)), sorted(answer2)) @@ -340,8 +359,9 @@ def test_subsets_unique(self): self.assertEqual(sorted(subsets_unique(nums1)), sorted(answer1)) nums2 = [1, 2, 3, 4] - answer2 = [(1, 2), (1, 3), (1, 2, 3, 4), (1,), (2,), (3,), (1, 4), (1, 2, 3), - (4,), (), (2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (3, 4), (2, 4)] + answer2 = [(1, 2), (1, 3), (1, 2, 3, 4), (1,), (2,), (3,), + (1, 4), (1, 2, 3), (4,), (), (2, 3), (1, 2, 4), + (1, 3, 4), (2, 3, 4), (3, 4), (2, 4)] self.assertEqual(sorted(subsets_unique(nums2)), sorted(answer2)) @@ -353,8 +373,9 @@ def test_subsets(self): self.assertEqual(sorted(subsets(nums1)), sorted(answer1)) nums2 = [1, 2, 3, 4] - answer2 = [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], - [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], [3, 4], [3], [4], []] + answer2 = [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], + [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], + [3, 4], [3], [4], []] self.assertEqual(sorted(subsets(nums2)), sorted(answer2)) def test_subsets_v2(self): @@ -363,8 +384,9 @@ def test_subsets_v2(self): self.assertEqual(sorted(subsets_v2(nums1)), sorted(answer1)) nums2 = [1, 2, 3, 4] - answer2 = [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], - [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], [3, 4], [3], [4], []] + answer2 = [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], + [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], + [3, 4], [3], [4], []] self.assertEqual(sorted(subsets_v2(nums2)), sorted(answer2)) diff --git a/tests/test_bfs.py b/tests/test_bfs.py index 98bcb7eb4..f9b22f134 100644 --- a/tests/test_bfs.py +++ b/tests/test_bfs.py @@ -1,7 +1,6 @@ from algorithms.bfs import ( count_islands, maze_search, - shortest_distance_from_all_buildings, ladder_length ) @@ -11,22 +10,27 @@ class TestCountIslands(unittest.TestCase): def test_count_islands(self): - grid_1 = [[1,1,1,1,0], [1,1,0,1,0], [1,1,0,0,0], [0,0,0,0,0]] + grid_1 = [[1, 1, 1, 1, 0], [1, 1, 0, 1, 0], [1, 1, 0, 0, 0], + [0, 0, 0, 0, 0]] self.assertEqual(1, count_islands(grid_1)) - grid_2 = [[1,1,0,0,0], [1,1,0,0,0], [0,0,1,0,0], [0,0,0,1,1]] + grid_2 = [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], + [0, 0, 0, 1, 1]] self.assertEqual(3, count_islands(grid_2)) - grid_3 = [[1,1,1,0,0,0], [1,1,0,0,0,0], [1,0,0,0,0,1], [0,0,1,1,0,1], [0,0,1,1,0,0]] + grid_3 = [[1, 1, 1, 0, 0, 0], [1, 1, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1], + [0, 0, 1, 1, 0, 1], [0, 0, 1, 1, 0, 0]] self.assertEqual(3, count_islands(grid_3)) - grid_4 = [[1,1,0,0,1,1], [0,0,1,1,0,0], [0,0,0,0,0,1], [1,1,1,1,0,0]] + grid_4 = [[1, 1, 0, 0, 1, 1], [0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1], + [1, 1, 1, 1, 0, 0]] self.assertEqual(5, count_islands(grid_4)) class TestMazeSearch(unittest.TestCase): def test_maze_search(self): - grid_1 = [[1,0,1,1,1,1],[1,0,1,0,1,0],[1,0,1,0,1,1],[1,1,1,0,1,1]] + grid_1 = [[1, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 1], + [1, 1, 1, 0, 1, 1]] self.assertEqual(14, maze_search(grid_1)) - grid_2 = [[1,0,0],[0,1,1],[0,1,1]] + grid_2 = [[1, 0, 0], [0, 1, 1], [0, 1, 1]] self.assertEqual(-1, maze_search(grid_2)) @@ -35,11 +39,13 @@ class TestWordLadder(unittest.TestCase): def test_ladder_length(self): # hit -> hot -> dot -> dog -> cog - self.assertEqual(5, ladder_length('hit', 'cog', ["hot", "dot", "dog", "lot", "log"])) + self.assertEqual(5, ladder_length('hit', 'cog', ["hot", "dot", "dog", + "lot", "log"])) # pick -> sick -> sink -> sank -> tank == 5 self.assertEqual(5, ladder_length('pick', 'tank', - ['tock', 'tick', 'sank', 'sink', 'sick'])) + ['tock', 'tick', 'sank', 'sink', + 'sick'])) # live -> life == 1, no matter what is the word_list. self.assertEqual(1, ladder_length('live', 'life', ['hoho', 'luck'])) @@ -48,7 +54,8 @@ def test_ladder_length(self): self.assertEqual(0, ladder_length('ate', 'ate', [])) # not possible to reach ! - self.assertEqual(-1, ladder_length('rahul', 'coder', ['blahh', 'blhah'])) + self.assertEqual(-1, ladder_length('rahul', 'coder', ['blahh', + 'blhah'])) if __name__ == "__main__": diff --git a/tests/test_bit.py b/tests/test_bit.py index 23e9d94f5..c494a9762 100644 --- a/tests/test_bit.py +++ b/tests/test_bit.py @@ -11,7 +11,7 @@ single_number3, subsets, get_bit, set_bit, clear_bit, update_bit, - int_to_bytes_big_endian, int_to_bytes_little_endian, + int_to_bytes_big_endian, int_to_bytes_little_endian, bytes_big_endian_to_int, bytes_little_endian_to_int, swap_pair, find_difference, @@ -151,20 +151,24 @@ def test_single_number2(self): self.assertEqual(single, single_number2(nums)) def test_single_number3(self): - self.assertEqual(sorted([2,5]), + self.assertEqual(sorted([2, 5]), sorted(single_number3([2, 1, 5, 6, 6, 1]))) - self.assertEqual(sorted([4,3]), + self.assertEqual(sorted([4, 3]), sorted(single_number3([9, 9, 4, 3]))) def test_subsets(self): self.assertSetEqual(subsets([1, 2, 3]), - {(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)}) + {(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), + (1, 2, 3)}) self.assertSetEqual(subsets([10, 20, 30, 40]), - {(10, 40), (10, 20, 40), (10, 30), (10, 20, 30, 40), (40,), - (10, 30, 40), (30,), (20, 30), (30, 40), (10,), (), - (10, 20), (20, 40), (20, 30, 40), (10, 20, 30), (20,)}) + {(10, 40), (10, 20, 40), (10, 30), + (10, 20, 30, 40), (40,), + (10, 30, 40), (30,), (20, 30), (30, 40), (10,), + (), + (10, 20), (20, 40), (20, 30, 40), (10, 20, 30), + (20,)}) def test_get_bit(self): # 22 = 10110 @@ -180,20 +184,22 @@ def test_clear_bit(self): self.assertEqual(18, clear_bit(22, 2)) def test_update_bit(self): - # 22 = 10110 --> after update bit at 3th position with value 1: 30 = 11110 + # 22 = 10110 --> after update bit at 3th position with + # value 1: 30 = 11110 self.assertEqual(30, update_bit(22, 3, 1)) - # 22 = 10110 --> after update bit at 2nd position with value 0: 20 = 10010 + # 22 = 10110 --> after update bit at 2nd position with + # value 0: 20 = 10010 self.assertEqual(18, update_bit(22, 2, 0)) def test_int_to_bytes_big_endian(self): self.assertEqual(b'\x11', int_to_bytes_big_endian(17)) - + def test_int_to_bytes_little_endian(self): self.assertEqual(b'\x11', int_to_bytes_little_endian(17)) def test_bytes_big_endian_to_int(self): self.assertEqual(17, bytes_big_endian_to_int(b'\x11')) - + def test_bytes_little_endian_to_int(self): self.assertEqual(17, bytes_little_endian_to_int(b'\x11')) diff --git a/tests/test_compression.py b/tests/test_compression.py index cd412839d..503369c4a 100644 --- a/tests/test_compression.py +++ b/tests/test_compression.py @@ -35,35 +35,40 @@ def tearDown(self): os.remove(self.file_out_bin_name) os.remove(self.file_out_name) + class TestRLECompression(unittest.TestCase): - + def test_encode_rle(self): self.assertEqual('12W1B12W3B24W1B14W', - encode_rle('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW')) + encode_rle('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW')) def test_decode_rle(self): - self.assertEqual('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW', - decode_rle('12W1B12W3B24W1B14W')) + self.assertEqual('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW', + decode_rle('12W1B12W3B24W1B14W')) + class TestEliasCoding(unittest.TestCase): def test_elias_gamma(self): - correct_result = ['0', '00', '100', '101', '11000', '11001', '11010', '11011', '1110000', '1110001', '1110010'] - + correct_result = ['0', '00', '100', '101', '11000', '11001', '11010', + '11011', '1110000', '1110001', '1110010'] + result = [] - for i in range(11): + for i in range(11): result.append(elias_gamma(i)) self.assertEqual(correct_result, result) def test_elias_delta(self): - correct_result = ['0', '000', '1000', '1001', '10100', '10101', '10110', '10111', '11000000', '11000001', '11000010'] + correct_result = ['0', '000', '1000', '1001', '10100', '10101', + '10110', '10111', '11000000', '11000001', '11000010'] result = [] - for i in range(11): + for i in range(11): result.append(elias_delta(i)) - self.assertEqual(correct_result, result) + self.assertEqual(correct_result, result) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_dfs.py b/tests/test_dfs.py index 0f198e4a9..3164ab873 100644 --- a/tests/test_dfs.py +++ b/tests/test_dfs.py @@ -12,53 +12,69 @@ class TestAllFactors(unittest.TestCase): def test_get_factors(self): - self.assertEqual([[2, 16], [2, 2, 8], [2, 2, 2, 4], [2, 2, 2, 2, 2], [2, 4, 4], [4, 8]], - get_factors(32)) + self.assertEqual([[2, 16], [2, 2, 8], [2, 2, 2, 4], [2, 2, 2, 2, 2], + [2, 4, 4], [4, 8]], get_factors(32)) + def test_get_factors_iterative1(self): - self.assertEqual([[2, 16], [4, 8], [2, 2, 8], [2, 4, 4], [2, 2, 2, 4], [2, 2, 2, 2, 2]], - get_factors_iterative1(32)) + self.assertEqual([[2, 16], [4, 8], [2, 2, 8], [2, 4, 4], [2, 2, 2, 4], + [2, 2, 2, 2, 2]], get_factors_iterative1(32)) + def test_get_factors_iterative2(self): - self.assertEqual([[2, 2, 2, 2, 2], [2, 2, 2, 4], [2, 2, 8], [2, 4, 4], [2, 16], [4, 8]], - get_factors_iterative2(32)) + self.assertEqual([[2, 2, 2, 2, 2], [2, 2, 2, 4], [2, 2, 8], [2, 4, 4], + [2, 16], [4, 8]], get_factors_iterative2(32)) class TestCountIslands(unittest.TestCase): def test_num_islands(self): - self.assertEqual(1, num_islands([[1, 1, 1, 1, 0], [1, 1, 0, 1, 0], [1, 1, 0, 0, 0], [0, 0, 0, 0, 0]])) - self.assertEqual(3, num_islands([[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]])) + self.assertEqual(1, num_islands([[1, 1, 1, 1, 0], [1, 1, 0, 1, 0], + [1, 1, 0, 0, 0], [0, 0, 0, 0, 0]])) + self.assertEqual(3, num_islands([[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], + [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]])) class TestPacificAtlantic(unittest.TestCase): def test_pacific_atlantic(self): - self.assertEqual([[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]], - pacific_atlantic([[1, 2, 2, 3, 5], [3, 2, 3, 4, 4], [2, 4, 5, 3, 1], [6, 7, 1, 4, 5], [5, 1, 1, 2, 4]])) + self.assertEqual([[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], + [3, 1], [4, 0]], pacific_atlantic([[1, 2, 2, 3, 5], + [3, 2, 3, 4, 4], + [2, 4, 5, 3, 1], + [6, 7, 1, 4, 5], + [5, 1, 1, 2, 4]])) class TestSudoku(unittest.TestCase): def test_sudoku_solver(self): - board = [["5","3","."], ["6",".", "."],[".","9","8"]] + board = [["5", "3", "."], ["6", ".", "."], [".", "9", "8"]] test_obj = Sudoku(board, 3, 3) test_obj.solve() - self.assertEqual([['5', '3', '1'], ['6', '1', '2'], ['1', '9', '8']],test_obj.board) + self.assertEqual([['5', '3', '1'], ['6', '1', '2'], + ['1', '9', '8']], test_obj.board) class TestWallsAndGates(unittest.TestCase): def test_walls_and_gates(self): - rooms = [[float("inf"), -1, 0, float("inf")], - [float("inf"), float("inf"), float("inf"), -1], - [float("inf"), -1, float("inf"), -1], - [0, -1, float("inf"), float("inf")]] + rooms = [[float("inf"), -1, 0, float("inf")], + [float("inf"), float("inf"), float("inf"), -1], + [float("inf"), -1, float("inf"), -1], + [0, -1, float("inf"), float("inf")]] walls_and_gates(rooms) - self.assertEqual([[3, -1, 0, 1], [2, 2, 1, -1], [1, -1, 2, -1], [0, -1, 3, 4]], rooms) + self.assertEqual([[3, -1, 0, 1], [2, 2, 1, -1], [1, -1, 2, -1], + [0, -1, 3, 4]], rooms) + class TestMazeSearch(unittest.TestCase): def test_maze_search(self): - maze_1 = [[1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1], [1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1]] + maze_1 = [[1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1], + [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1]] self.assertEqual(37, find_path(maze_1)) - maze_2 = [[1,0,1,1,1,1], [1,0,1,0,1,0], [1,0,1,0,1,1], [1,1,1,0,1,1]] + maze_2 = [[1, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0], + [1, 0, 1, 0, 1, 1], [1, 1, 1, 0, 1, 1]] self.assertEqual(14, find_path(maze_2)) - maze_3 = [[1,0,0], [0,1,1], [0,1,1]] + maze_3 = [[1, 0, 0], [0, 1, 1], [0, 1, 1]] self.assertEqual(-1, find_path(maze_3)) + if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_dp.py b/tests/test_dp.py index 300be3d85..e8dca0bce 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -11,9 +11,7 @@ Job, schedule, Item, get_maximum_value, longest_increasing_subsequence, - longest_increasing_subsequence_optimized, - longest_increasing_subsequence_optimized2, - int_divide,find_k_factor, + int_divide, find_k_factor, planting_trees ) @@ -85,7 +83,7 @@ def test_fib_iter(self): class TestHosoyaTriangle(unittest.TestCase): """[summary] Test for the file hosoya_triangle - + Arguments: unittest {[type]} -- [description] """ @@ -109,7 +107,7 @@ def test_hosoya(self): 21, 13, 16, 15, 15, 16, 13, 21, 34, 21, 26, 24, 25, 24, 26, 21, 34, 55, 34, 42, 39, 40, 40, 39, 42, 34, 55], - hosoya_testing(10)) + hosoya_testing(10)) class TestHouseRobber(unittest.TestCase): @@ -129,7 +127,8 @@ def test_get_maximum_value(self): self.assertEqual(220, get_maximum_value([item1, item2, item3], 50)) item1, item2, item3, item4 = Item(60, 5), Item(50, 3), Item(70, 4), Item(30, 2) - self.assertEqual(80, get_maximum_value([item1, item2, item3, item4], 5)) + self.assertEqual(80, get_maximum_value([item1, item2, item3, item4], + 5)) class TestLongestIncreasingSubsequence(unittest.TestCase): @@ -156,32 +155,34 @@ def test_int_divide(self): self.assertEqual(42, int_divide(10)) self.assertEqual(204226, int_divide(50)) + class Test_dp_K_Factor(unittest.TestCase): def test_kfactor(self): - #Test 1 - n1=4 - k1=1 - self.assertEqual(find_k_factor(n1,k1),1) - - #Test 2 - n2=7 - k2=1 - self.assertEqual(find_k_factor(n2,k2),70302) - - #Test 3 - n3=10 - k3=2 - self.assertEqual(find_k_factor(n3,k3),74357) - - #Test 4 - n4=8 - k4=2 - self.assertEqual(find_k_factor(n4,k4),53) - - #Test 5 - n5=9 - k5=1 - self.assertEqual(find_k_factor(n5,k5),71284044) + # Test 1 + n1 = 4 + k1 = 1 + self.assertEqual(find_k_factor(n1, k1), 1) + + # Test 2 + n2 = 7 + k2 = 1 + self.assertEqual(find_k_factor(n2, k2), 70302) + + # Test 3 + n3 = 10 + k3 = 2 + self.assertEqual(find_k_factor(n3, k3), 74357) + + # Test 4 + n4 = 8 + k4 = 2 + self.assertEqual(find_k_factor(n4, k4), 53) + + # Test 5 + n5 = 9 + k5 = 1 + self.assertEqual(find_k_factor(n5, k5), 71284044) + class TestPlantingTrees(unittest.TestCase): def test_simple(self): @@ -208,5 +209,6 @@ def test_simple2(self): # assert self.assertEqual(res, 9.28538328578604) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_graph.py b/tests/test_graph.py index 325b5d896..8caf858e7 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -8,7 +8,6 @@ from algorithms.graph import maximum_flow_dfs from algorithms.graph import all_pairs_shortest_path from algorithms.graph import bellman_ford -from algorithms.graph import bellman_ford from algorithms.graph import count_connected_number_of_component from algorithms.graph import prims_minimum_spanning @@ -37,7 +36,8 @@ def test_tarjan_example_1(self): } g = Tarjan(example) - self.assertEqual(g.sccs, [['F', 'G'], ['C', 'D', 'H'], ['A', 'B', 'E']]) + self.assertEqual(g.sccs, [['F', 'G'], ['C', 'D', 'H'], + ['A', 'B', 'E']]) def test_tarjan_example_2(self): # Graph from https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm#/media/File:Tarjan%27s_Algorithm_Animation.gif @@ -53,39 +53,36 @@ def test_tarjan_example_2(self): } g = Tarjan(example) - self.assertEqual(g.sccs, [['A', 'B', 'E'], ['C', 'D'], ['F', 'G'], ['H']]) + self.assertEqual(g.sccs, [['A', 'B', 'E'], ['C', 'D'], ['F', 'G'], + ['H']]) + - class TestCheckBipartite(unittest.TestCase): - def test_check_bipartite(self): - adj_list_1 = [[0, 0, 1], [0, 0, 1], [1, 1, 0]] self.assertEqual(True, check_bipartite(adj_list_1)) - adj_list_2 = [[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 1, 0]] self.assertEqual(True, check_bipartite(adj_list_2)) - adj_list_3 = [[0, 1, 0, 0], [1, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 0]] self.assertEqual(False, check_bipartite(adj_list_3)) + class TestDijkstra(unittest.TestCase): - def test_dijkstra(self): - g = Dijkstra(9) - g.graph = [[0, 4, 0, 0, 0, 0, 0, 8, 0], - [4, 0, 8, 0, 0, 0, 0, 11, 0], - [0, 8, 0, 7, 0, 4, 0, 0, 2], - [0, 0, 7, 0, 9, 14, 0, 0, 0], - [0, 0, 0, 9, 0, 10, 0, 0, 0], - [0, 0, 4, 14, 10, 0, 2, 0, 0], - [0, 0, 0, 0, 0, 2, 0, 1, 6], - [8, 11, 0, 0, 0, 0, 1, 0, 7], - [0, 0, 2, 0, 0, 0, 6, 7, 0] - ]; + g = Dijkstra(9) + g.graph = [[0, 4, 0, 0, 0, 0, 0, 8, 0], + [4, 0, 8, 0, 0, 0, 0, 11, 0], + [0, 8, 0, 7, 0, 4, 0, 0, 2], + [0, 0, 7, 0, 9, 14, 0, 0, 0], + [0, 0, 0, 9, 0, 10, 0, 0, 0], + [0, 0, 4, 14, 10, 0, 2, 0, 0], + [0, 0, 0, 0, 0, 2, 0, 1, 6], + [8, 11, 0, 0, 0, 0, 1, 0, 7], + [0, 0, 2, 0, 0, 0, 6, 7, 0]] self.assertEqual(g.dijkstra(0), [0, 4, 12, 19, 21, 11, 9, 8, 14]) + class TestMaximumFlow(unittest.TestCase): """ Test for the file maximum_flow.py @@ -104,6 +101,7 @@ def test_ford_fulkerson(self): [0, 0, 0, 0, 0, 0, 0] ] self.assertEqual(19, ford_fulkerson(capacity, 0, 6)) + def test_edmonds_karp(self): capacity = [ [0, 10, 10, 0, 0, 0, 0], @@ -115,6 +113,7 @@ def test_edmonds_karp(self): [0, 0, 0, 0, 0, 0, 0] ] self.assertEqual(19, edmonds_karp(capacity, 0, 6)) + def dinic(self): capacity = [ [0, 10, 10, 0, 0, 0, 0], @@ -127,6 +126,7 @@ def dinic(self): ] self.assertEqual(19, dinic(capacity, 0, 6)) + class TestMaximum_Flow_Bfs(unittest.TestCase): """ @@ -134,13 +134,12 @@ class TestMaximum_Flow_Bfs(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ - def test_maximum_flow_bfs(self): graph = [ [0, 16, 13, 0, 0, 0], [0, 0, 10, 12, 0, 0], - [0, 4, 0, 0, 14, 0], - [0, 0, 9, 0, 0, 20], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], [0, 0, 0, 7, 0, 4], [0, 0, 0, 0, 0, 0] ] @@ -148,6 +147,7 @@ def test_maximum_flow_bfs(self): self.assertEqual(maximum_flow, 23) + class TestMaximum_Flow_Dfs(unittest.TestCase): """ @@ -155,13 +155,12 @@ class TestMaximum_Flow_Dfs(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ - def test_maximum_flow_dfs(self): graph = [ [0, 16, 13, 0, 0, 0], [0, 0, 10, 12, 0, 0], - [0, 4, 0, 0, 14, 0], - [0, 0, 9, 0, 0, 20], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], [0, 0, 0, 7, 0, 4], [0, 0, 0, 0, 0, 0] ] @@ -171,24 +170,26 @@ def test_maximum_flow_dfs(self): class TestAll_Pairs_Shortest_Path(unittest.TestCase): - def test_all_pairs_shortest_path(self): - graph = [[0, 0.1, 0.101, 0.142, 0.277], - [0.465, 0, 0.191, 0.192, 0.587], - [0.245, 0.554, 0, 0.333, 0.931], - [1.032, 0.668, 0.656, 0, 0.151], + graph = [[0, 0.1, 0.101, 0.142, 0.277], + [0.465, 0, 0.191, 0.192, 0.587], + [0.245, 0.554, 0, 0.333, 0.931], + [1.032, 0.668, 0.656, 0, 0.151], [0.867, 0.119, 0.352, 0.398, 0]] result = all_pairs_shortest_path(graph) self.assertEqual(result, [ - [0, 0.1, 0.101, 0.142, 0.277], - [0.436, 0, 0.191, 0.192, 0.34299999999999997], - [0.245, 0.345, 0, 0.333, 0.484], - [0.706, 0.27, 0.46099999999999997, 0, 0.151], - [0.5549999999999999, 0.119, 0.31, 0.311, 0], - ]) - - + [0, 0.1, 0.101, 0.142, 0.277], + [0.436, 0, 0.191, 0.192, + 0.34299999999999997], + [0.245, 0.345, 0, 0.333, 0.484], + [0.706, 0.27, 0.46099999999999997, 0, + 0.151], + [0.5549999999999999, 0.119, 0.31, 0.311, + 0], + ]) + + class TestBellmanFord(unittest.TestCase): def test_bellman_ford(self): graph1 = { @@ -198,90 +199,82 @@ def test_bellman_ford(self): 'd': {'a': 2, 'c': 7}, 'e': {'b': -3} } - self.assertEqual(True, bellman_ford(graph1, 'a')) - graph2 = { 'a': {'d': 3, 'e': 4}, - 'b': {'a': 7, 'e':2}, - 'c': {'a': 12, 'd':9, 'e':11}, + 'b': {'a': 7, 'e': 2}, + 'c': {'a': 12, 'd': 9, 'e': 11}, 'd': {'c': 5, 'e': 11}, 'e': {'a': 7, 'b': 5, 'd': 1} - } - + } self.assertEqual(True, bellman_ford(graph2, 'a')) - -class TestConnectedComponentInGraph(unittest.TestCase): + +class TestConnectedComponentInGraph(unittest.TestCase): """ Class for testing different cases for connected components in graph """ def test_count_connected_components(self): """ - Test Function that test the different cases of count connected components - + Test Function that test the different cases of count connected + components 2----------0 1--------5 3 | | 4 - output = 3 """ expected_result = 3 - # adjacency list representation of graph l = [[2], - [5], - [0,4], - [], - [2], - [1] - ] + [5], + [0,4], + [], + [2], + [1]] size = 5 - result = count_connected_number_of_component.count_components(l,size) - self.assertEqual(result,expected_result) + result = count_connected_number_of_component.count_components(l, size) + self.assertEqual(result, expected_result) def test_connected_components_with_empty_graph(self): """ - input : + input : output : 0 """ - l = [[]] expected_result = 0 size = 0 - result = count_connected_number_of_component.count_components(l,size) - self.assertEqual(result,expected_result) + result = count_connected_number_of_component.count_components(l, size) + self.assertEqual(result, expected_result) def test_connected_components_without_edges_graph(self): """ input : 0 2 3 4 output : 4 - """ - l = [[0],[],[2],[3],[4]] + """ + l = [[0], [], [2], [3], [4]] size = 4 expected_result = 4 - result = count_connected_number_of_component.count_components(l,size) - self.assertEqual(result,expected_result) + result = count_connected_number_of_component.count_components(l, size) + self.assertEqual(result, expected_result) + - class PrimsMinimumSpanning(unittest.TestCase): def test_prim_spanning(self): graph1 = { - 1 : [ [3, 2], [8, 3] ], - 2 : [ [3, 1], [5, 4] ], - 3 : [ [8, 1], [2, 4], [4, 5] ], - 4 : [ [5, 2], [2, 3], [6, 5] ], - 5 : [ [4, 3], [6, 4] ] + 1: [[3, 2], [8, 3]], + 2: [[3, 1], [5, 4]], + 3: [[8, 1], [2, 4], [4, 5]], + 4: [[5, 2], [2, 3], [6, 5]], + 5: [[4, 3], [6, 4]] } self.assertEqual(14, prims_minimum_spanning(graph1)) - graph2 = { - 1 : [ [7, 2], [6, 4] ], - 2 : [ [7, 1], [9, 4], [6, 3] ], - 3 : [ [8, 4], [6, 2] ], - 4 : [ [6, 1], [9, 2], [8, 3] ] + 1: [[7, 2], [6, 4]], + 2: [[7, 1], [9, 4], [6, 3]], + 3: [[8, 4], [6, 2]], + 4: [[6, 1], [9, 2], [8, 3]] } self.assertEqual(19, prims_minimum_spanning(graph2)) diff --git a/tests/test_heap.py b/tests/test_heap.py index 6814c6196..11e323e5f 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -55,10 +55,12 @@ def test_max_sliding_window(self): self.assertEqual([3, 3, 5, 5, 6, 7], max_sliding_window(nums, 3)) def test_k_closest_points(self): - points = [(1, 0), (2, 3), (5, 2), (1, 1), (2, 8), (10, 2), (-1, 0), (-2, -2)] + points = [(1, 0), (2, 3), (5, 2), (1, 1), (2, 8), (10, 2), + (-1, 0), (-2, -2)] self.assertEqual([(-1, 0), (1, 0)], k_closest(points, 2)) self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest(points, 3)) - self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest(points, 4)) + self.assertEqual([(-2, -2), (1, 1), (1, 0), + (-1, 0)], k_closest(points, 4)) self.assertEqual([(10, 2), (2, 8), (5, 2), (-2, -2), (2, 3), (1, 0), (-1, 0), (1, 1)], k_closest(points, 8)) diff --git a/tests/test_iterative_segment_tree.py b/tests/test_iterative_segment_tree.py index b9a611a05..77c0283ba 100644 --- a/tests/test_iterative_segment_tree.py +++ b/tests/test_iterative_segment_tree.py @@ -21,10 +21,14 @@ def test_segment_tree_creation(self): min_segment_tree = SegmentTree(arr, min) sum_segment_tree = SegmentTree(arr, lambda a, b: a + b) gcd_segment_tree = SegmentTree(arr, gcd) - self.assertEqual(max_segment_tree.tree, [None, 9, 8, 9, 4, 8, 9, 2, 4, 3, 6, 8, 9, 3]) - self.assertEqual(min_segment_tree.tree, [None, 2, 3, 2, 3, 6, 3, 2, 4, 3, 6, 8, 9, 3]) - self.assertEqual(sum_segment_tree.tree, [None, 35, 21, 14, 7, 14, 12, 2, 4, 3, 6, 8, 9, 3]) - self.assertEqual(gcd_segment_tree.tree, [None, 1, 1, 1, 1, 2, 3, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(max_segment_tree.tree, + [None, 9, 8, 9, 4, 8, 9, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(min_segment_tree.tree, + [None, 2, 3, 2, 3, 6, 3, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(sum_segment_tree.tree, + [None, 35, 21, 14, 7, 14, 12, 2, 4, 3, 6, 8, 9, 3]) + self.assertEqual(gcd_segment_tree.tree, + [None, 1, 1, 1, 1, 2, 3, 2, 4, 3, 6, 8, 9, 3]) def test_max_segment_tree(self): arr = [-1, 1, 10, 2, 9, -3, 8, 4, 7, 5, 6, 0] @@ -44,22 +48,26 @@ def test_gcd_segment_tree(self): def test_max_segment_tree_with_updates(self): arr = [-1, 1, 10, 2, 9, -3, 8, 4, 7, 5, 6, 0] - updates = {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 11, 11: 12} + updates = {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, + 9: 10, 10: 11, 11: 12} self.__test_all_segments_with_updates(arr, max, updates) def test_min_segment_tree_with_updates(self): arr = [1, 10, -2, 9, -3, 8, 4, -7, 5, 6, 11, -12] - updates = {0: 7, 1: 2, 2: 6, 3: -14, 4: 5, 5: 4, 6: 7, 7: -10, 8: 9, 9: 10, 10: 12, 11: 1} + updates = {0: 7, 1: 2, 2: 6, 3: -14, 4: 5, 5: 4, 6: 7, 7: -10, 8: 9, + 9: 10, 10: 12, 11: 1} self.__test_all_segments_with_updates(arr, min, updates) def test_sum_segment_tree_with_updates(self): arr = [1, 10, 2, 9, 3, 8, 4, 7, 5, 6, -11, -12] - updates = {0: 12, 1: 11, 2: 10, 3: 9, 4: 8, 5: 7, 6: 6, 7: 5, 8: 4, 9: 3, 10: 2, 11: 1} + updates = {0: 12, 1: 11, 2: 10, 3: 9, 4: 8, 5: 7, 6: 6, 7: 5, 8: 4, + 9: 3, 10: 2, 11: 1} self.__test_all_segments_with_updates(arr, lambda a, b: a + b, updates) def test_gcd_segment_tree_with_updates(self): arr = [1, 10, 2, 9, 3, 8, 4, 7, 5, 6, 11, 12, 14] - updates = {0: 4, 1: 2, 2: 3, 3: 9, 4: 21, 5: 7, 6: 4, 7: 4, 8: 2, 9: 5, 10: 17, 11: 12, 12: 3} + updates = {0: 4, 1: 2, 2: 3, 3: 9, 4: 21, 5: 7, 6: 4, 7: 4, 8: 2, + 9: 5, 10: 17, 11: 12, 12: 3} self.__test_all_segments_with_updates(arr, gcd, updates) def __test_all_segments(self, arr, fnc): diff --git a/tests/test_map.py b/tests/test_map.py index c8164881b..a62656d15 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -1,6 +1,6 @@ from algorithms.map import ( HashTable, ResizableHashTable, - Node, SeparateChainingHashTable, + SeparateChainingHashTable, word_pattern, is_isomorphic, is_anagram, @@ -9,6 +9,7 @@ import unittest + class TestHashTable(unittest.TestCase): def test_one_entry(self): m = HashTable(10) @@ -45,7 +46,7 @@ def test_delete_key(self): m.put(i, i**2) m.del_(1) self.assertEqual(None, m.get(1)) - self.assertEqual(4,m.get(2)) + self.assertEqual(4, m.get(2)) def test_delete_key_and_reassign(self): m = HashTable(10) @@ -91,9 +92,9 @@ def test_resizable_hash_table(self): def test_fill_up_the_limit(self): m = HashTable(10) for i in range(10): - m.put(i,i**2) + m.put(i, i**2) for i in range(10): - self.assertEqual(i**2,m.get(i)) + self.assertEqual(i**2, m.get(i)) class TestSeparateChainingHashTable(unittest.TestCase): @@ -165,18 +166,20 @@ def test_is_isomorphic(self): self.assertFalse(is_isomorphic("foo", "bar")) self.assertTrue(is_isomorphic("paper", "title")) + class TestLongestPalindromicSubsequence(unittest.TestCase): def test_longest_palindromic_subsequence_is_correct(self): - self.assertEqual(3,longest_palindromic_subsequence('BBABCBCAB')) - self.assertEqual(4,longest_palindromic_subsequence('abbaeae')) - self.assertEqual(7,longest_palindromic_subsequence('babbbababaa')) - self.assertEqual(4,longest_palindromic_subsequence('daccandeeja')) + self.assertEqual(3, longest_palindromic_subsequence('BBABCBCAB')) + self.assertEqual(4, longest_palindromic_subsequence('abbaeae')) + self.assertEqual(7, longest_palindromic_subsequence('babbbababaa')) + self.assertEqual(4, longest_palindromic_subsequence('daccandeeja')) def test_longest_palindromic_subsequence_is_incorrect(self): - self.assertNotEqual(4,longest_palindromic_subsequence('BBABCBCAB')) - self.assertNotEqual(5,longest_palindromic_subsequence('abbaeae')) - self.assertNotEqual(2,longest_palindromic_subsequence('babbbababaa')) - self.assertNotEqual(1,longest_palindromic_subsequence('daccandeeja')) + self.assertNotEqual(4, longest_palindromic_subsequence('BBABCBCAB')) + self.assertNotEqual(5, longest_palindromic_subsequence('abbaeae')) + self.assertNotEqual(2, longest_palindromic_subsequence('babbbababaa')) + self.assertNotEqual(1, longest_palindromic_subsequence('daccandeeja')) + class TestIsAnagram(unittest.TestCase): def test_is_anagram(self): @@ -184,7 +187,5 @@ def test_is_anagram(self): self.assertFalse(is_anagram("rat", "car")) - - if __name__ == "__main__": unittest.main() diff --git a/tests/test_maths.py b/tests/test_maths.py index 967cf64d9..ec8f65798 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -22,9 +22,7 @@ magic_number, find_order, find_primitive_root, - alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, num_digits, - alice_private_key, alice_public_key, bob_private_key, bob_public_key, alice_shared_key, bob_shared_key, diffie_hellman_key_exchange, krishnamurthy_number, chinese_remainder_theorem, ) @@ -131,13 +129,15 @@ def test_gcd(self): self.assertEqual(1, gcd(13, 17)) def test_gcd_non_integer_input(self): - with pytest.raises(ValueError, match=r"Input arguments are not integers"): + with pytest.raises(ValueError, + match=r"Input arguments are not integers"): gcd(1.0, 5) gcd(5, 6.7) gcd(33.8649, 6.12312312) def test_gcd_zero_input(self): - with pytest.raises(ValueError, match=r"One or more input arguments equals zero"): + with pytest.raises(ValueError, + match=r"One or more input arguments equals zero"): gcd(0, 12) gcd(12, 0) gcd(0, 0) @@ -157,7 +157,8 @@ def test_lcm_negative_numbers(self): self.assertEqual(1, lcm(-1, 1)) def test_lcm_zero_input(self): - with pytest.raises(ValueError, match=r"One or more input arguments equals zero"): + with pytest.raises(ValueError, + match=r"One or more input arguments equals zero"): lcm(0, 12) lcm(12, 0) lcm(0, 0) @@ -171,7 +172,6 @@ def test_gcd_bit(self): self.assertEqual(1, gcd(13, 17)) - class TestGenerateStroboGrammatic(unittest.TestCase): """[summary] Test for the file generate_strobogrammatic.py @@ -216,7 +216,8 @@ def test_modular_inverse(self): # checks if x * x_inv == 1 (mod m) self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 19) % 19) self.assertEqual(1, 53 * modular_inverse.modular_inverse(53, 91) % 91) - self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 1000000007) % 1000000007) + self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 1000000007) + % 1000000007) self.assertRaises(ValueError, modular_inverse.modular_inverse, 2, 20) @@ -295,7 +296,8 @@ class TestPythagoras(unittest.TestCase): """ def test_pythagoras(self): - self.assertEqual("Hypotenuse = 3.605551275463989", pythagoras(3, 2, "?")) + self.assertEqual("Hypotenuse = 3.605551275463989", + pythagoras(3, 2, "?")) class TestRabinMiller(unittest.TestCase): @@ -417,7 +419,8 @@ def test_find_primitive_root_simple(self): self.assertListEqual([0], find_primitive_root(1)) self.assertListEqual([2, 3], find_primitive_root(5)) self.assertListEqual([], find_primitive_root(24)) - self.assertListEqual([2, 5, 13, 15, 17, 18, 19, 20, 22, 24, 32, 35], find_primitive_root(37)) + self.assertListEqual([2, 5, 13, 15, 17, 18, 19, 20, 22, 24, 32, 35], + find_primitive_root(37)) class TestFindOrder(unittest.TestCase): @@ -434,6 +437,7 @@ def test_find_order_simple(self): self.assertEqual(-1, find_order(128, 256)) self.assertEqual(352, find_order(3, 353)) + class TestKrishnamurthyNumber(unittest.TestCase): """[summary] Test for the file krishnamurthy_number.py @@ -441,7 +445,7 @@ class TestKrishnamurthyNumber(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ - + def test_krishnamurthy_number(self): self.assertFalse(krishnamurthy_number(0)) self.assertTrue(krishnamurthy_number(2)) @@ -490,12 +494,13 @@ class TestNumberOfDigits(unittest.TestCase): unittest {[type]} -- [description] """ def test_num_digits(self): - self.assertEqual(2,num_digits(12)) - self.assertEqual(5,num_digits(99999)) - self.assertEqual(1,num_digits(8)) - self.assertEqual(1,num_digits(0)) - self.assertEqual(1,num_digits(-5)) - self.assertEqual(3,num_digits(-254)) + self.assertEqual(2, num_digits(12)) + self.assertEqual(5, num_digits(99999)) + self.assertEqual(1, num_digits(8)) + self.assertEqual(1, num_digits(0)) + self.assertEqual(1, num_digits(-5)) + self.assertEqual(3, num_digits(-254)) + class TestChineseRemainderSolver(unittest.TestCase): def test_k_three(self): @@ -504,7 +509,8 @@ def test_k_three(self): # solves the system of equations num = [3, 7, 10] rem = [2, 3, 3] - self.assertEqual(chinese_remainder_theorem.solve_chinese_remainder(num, rem), 143) + self.assertEqual(chinese_remainder_theorem. + solve_chinese_remainder(num, rem), 143) def test_k_five(self): # Example which should give the answer 3383 @@ -512,7 +518,8 @@ def test_k_five(self): # solves the system of equations num = [3, 5, 7, 11, 26] rem = [2, 3, 2, 6, 3] - self.assertEqual(chinese_remainder_theorem.solve_chinese_remainder(num, rem), 3383) + self.assertEqual(chinese_remainder_theorem. + solve_chinese_remainder(num, rem), 3383) def test_exception_non_coprime(self): # There should be an exception when all @@ -528,5 +535,6 @@ def test_empty_lists(self): with self.assertRaises(Exception): chinese_remainder_theorem.solve_chinese_remainder(num, rem) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 667dc1670..262fdbe62 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -51,16 +51,20 @@ class TestCopyTransform(unittest.TestCase): def test_copy_transform(self): self.assertEqual(copy_transform.rotate_clockwise( - [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), + [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) self.assertEqual(copy_transform.rotate_counterclockwise( - [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[3, 6, 9], [2, 5, 8], [1, 4, 7]]) + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), + [[3, 6, 9], [2, 5, 8], [1, 4, 7]]) self.assertEqual(copy_transform.top_left_invert( - [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[1, 4, 7], [2, 5, 8], [3, 6, 9]]) + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), + [[1, 4, 7], [2, 5, 8], [3, 6, 9]]) self.assertEqual(copy_transform.bottom_left_invert( - [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[9, 6, 3], [8, 5, 2], [7, 4, 1]]) + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), + [[9, 6, 3], [8, 5, 2], [7, 4, 1]]) class TestCroutMatrixDecomposition(unittest.TestCase): @@ -95,7 +99,8 @@ def test_crout_matrix_decomposition(self): [0, 0, 1.0, 0.0], [0, 0, 0, 1.0]]), crout_matrix_decomposition.crout_matrix_decomposition( - [[2, 1, 3, 1], [4, 1, 4, 1], [6, 1, 7, 1], [8, 1, 9, 1]])) + [[2, 1, 3, 1], [4, 1, 4, 1], [6, 1, 7, 1], + [8, 1, 9, 1]])) class TestCholeskyMatrixDecomposition(unittest.TestCase): @@ -119,14 +124,16 @@ def test_cholesky_matrix_decomposition(self): self.assertEqual(None, cholesky_matrix_decomposition.cholesky_decomposition( - [[4, 12, -16], [12, 37, -43], [-16, -43, 98], [1, 2, 3]])) + [[4, 12, -16], [12, 37, -43], [-16, -43, 98], + [1, 2, 3]])) # example taken from https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/04LinearAlgebra/cholesky/ self.assertEqual([[2.23606797749979, 0.0, 0.0, 0.0], [0.5366563145999494, 2.389979079406345, 0.0, 0.0], [0.13416407864998736, -0.19749126846635062, 2.818332343581848, 0.0], - [-0.2683281572999747, 0.43682390737048743, 0.64657701271919, 3.052723872310221]], + [-0.2683281572999747, 0.43682390737048743, + 0.64657701271919, 3.052723872310221]], cholesky_matrix_decomposition.cholesky_decomposition( [[5, 1.2, 0.3, -0.6], [1.2, 6, -0.4, 0.9], [0.3, -0.4, 8, 1.7], [-0.6, 0.9, 1.7, 10]])) @@ -160,11 +167,16 @@ def test_inversion(self): self.assertEqual(matrix_inversion.invert_matrix(m5), [[-4]]) m6 = [[3, 5, 1], [2, 5, 0], [1, 9, 8]] - self.assertEqual(matrix_inversion.invert_matrix(m6), [[Fraction(40, 53), Fraction(-31, 53), Fraction(-5, 53)], - [Fraction(-16, 53), Fraction( - 23, 53), Fraction(2, 53)], - [Fraction(13, 53), Fraction(-22, 53), Fraction(5, 53)]]) - + self.assertEqual(matrix_inversion.invert_matrix(m6), + [[Fraction(40, 53), + Fraction(-31, 53), + Fraction(-5, 53)], + [Fraction(-16, 53), + Fraction(23, 53), + Fraction(2, 53)], + [Fraction(13, 53), + Fraction(-22, 53), + Fraction(5, 53)]]) class TestMatrixExponentiation(unittest.TestCase): @@ -179,16 +191,16 @@ def test_matrix_exponentiation(self): mat = [[1, 0, 2], [2, 1, 0], [0, 2, 1]] self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 0), - [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 1), - [[1, 0, 2], [2, 1, 0], [0, 2, 1]]) + [[1, 0, 2], [2, 1, 0], [0, 2, 1]]) self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 2), - [[1, 4, 4], [4, 1, 4], [4, 4, 1]]) + [[1, 4, 4], [4, 1, 4], [4, 4, 1]]) self.assertEqual(matrix_exponentiation.matrix_exponentiation(mat, 5), - [[81, 72, 90], [90, 81, 72], [72, 90, 81]]) + [[81, 72, 90], [90, 81, 72], [72, 90, 81]]) class TestMultiply(unittest.TestCase): @@ -214,7 +226,8 @@ class TestRotateImage(unittest.TestCase): def test_rotate_image(self): self.assertEqual(rotate_image.rotate( - [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), + [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) class TestSparseDotVector(unittest.TestCase): @@ -226,8 +239,12 @@ class TestSparseDotVector(unittest.TestCase): """ def test_sparse_dot_vector(self): - self.assertEqual(sparse_dot_vector.dot_product(sparse_dot_vector.vector_to_index_value_list( - [1., 2., 3.]), sparse_dot_vector.vector_to_index_value_list([0., 2., 2.])), 10) + self.assertEqual(sparse_dot_vector. + dot_product(sparse_dot_vector. + vector_to_index_value_list([1., 2., 3.]), + sparse_dot_vector. + vector_to_index_value_list([0., 2., 2.])), + 10) class TestSpiralTraversal(unittest.TestCase): diff --git a/tests/test_ml.py b/tests/test_ml.py index 61852ec31..1622ae1a8 100644 --- a/tests/test_ml.py +++ b/tests/test_ml.py @@ -5,27 +5,36 @@ import unittest + class TestML(unittest.TestCase): def setUp(self): # train set for the AND-function - self.trainSetAND = {(0,0) : 0, (0,1) :0, (1,0) : 0, (1,1) : 1} + self.trainSetAND = {(0, 0): 0, (0, 1): 0, (1, 0): 0, (1, 1): 1} # train set for light or dark colors - self.trainSetLight = {(11, 98, 237) : 'L', (3, 39, 96) : 'D', (242, 226, 12) : 'L', (99, 93, 4) : 'D', - (232, 62, 32) : 'L', (119, 28, 11) : 'D', (25, 214, 47) : 'L', (89, 136, 247) : 'L', - (21, 34, 63) : 'D', (237, 99, 120) : 'L', (73, 33, 39) : 'D'} + self.trainSetLight = {(11, 98, 237): 'L', (3, 39, 96): 'D', + (242, 226, 12): 'L', (99, 93, 4): 'D', + (232, 62, 32): 'L', (119, 28, 11): 'D', + (25, 214, 47): 'L', (89, 136, 247): 'L', + (21, 34, 63): 'D', (237, 99, 120): 'L', + (73, 33, 39): 'D'} + def test_nearest_neighbor(self): # AND-function - self.assertEqual(nearest_neighbor((1,1), self.trainSetAND), 1) - self.assertEqual(nearest_neighbor((0,1), self.trainSetAND), 0) + self.assertEqual(nearest_neighbor((1, 1), self.trainSetAND), 1) + self.assertEqual(nearest_neighbor((0, 1), self.trainSetAND), 0) # dark/light color test - self.assertEqual(nearest_neighbor((31, 242, 164), self.trainSetLight), 'L') - self.assertEqual(nearest_neighbor((13, 94, 64), self.trainSetLight), 'D') - self.assertEqual(nearest_neighbor((230, 52, 239), self.trainSetLight), 'L') + self.assertEqual(nearest_neighbor((31, 242, 164), + self.trainSetLight), 'L') + self.assertEqual(nearest_neighbor((13, 94, 64), + self.trainSetLight), 'D') + self.assertEqual(nearest_neighbor((230, 52, 239), + self.trainSetLight), 'L') + def test_distance(self): - self.assertAlmostEqual(distance((1,2,3), (1,0,-1)), 4.47, 2) + self.assertAlmostEqual(distance((1, 2, 3), (1, 0, -1)), 4.47, 2) + - if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_monomial.py b/tests/test_monomial.py index 8e4667d83..31e56f79b 100644 --- a/tests/test_monomial.py +++ b/tests/test_monomial.py @@ -5,8 +5,9 @@ import unittest + class TestSuite(unittest.TestCase): - + def setUp(self): self.m1 = Monomial({}) self.m2 = Monomial({1: 1}, 2) @@ -15,7 +16,7 @@ def setUp(self): self.m5 = Monomial({2: 1, 3: 0}, Fraction(2, 3)) self.m6 = Monomial({1: 0, 2: 0, 3: 0}, -2.27) self.m7 = Monomial({1: 2, 7: 2}, -math.pi) - self.m8 = Monomial({150: 5, 170: 2, 10000:3}, 0) + self.m8 = Monomial({150: 5, 170: 2, 10000: 3}, 0) self.m9 = 2 self.m10 = math.pi self.m11 = Fraction(3, 8) @@ -39,10 +40,11 @@ def test_monomial_addition(self): # Zero monomial + Zero monomial = Zero monomial self.assertEqual(self.m1 + self.m1, self.m1) - + # Coefficient float. - self.assertEqual(self.m7 + self.m7, Monomial({1: 2, 7: 2}, -2*math.pi)) - + self.assertEqual(self.m7 + self.m7, Monomial({1: 2, 7: 2}, + -2 * math.pi)) + # Coefficient 0 so should equal the zero monomial. self.assertEqual(self.m8, self.m1) @@ -77,13 +79,13 @@ def test_monomial_subtraction(self): # Zero monomial - Zero monomial = Zero monomial self.assertEqual(self.m1 - self.m1, self.m1) - + # Coefficient int. self.assertEqual(self.m2 - self.m15, Monomial({1: 1}, -1)) - - # Coefficient float. - self.assertEqual(self.m16 - self.m7, Monomial({1: 2, 7: 2}, 2*math.pi)) + # Coefficient float. + self.assertEqual(self.m16 - self.m7, Monomial({1: 2, 7: 2}, + 2 * math.pi)) # The constant term cannot be added to any monomial # that has any variables. @@ -103,7 +105,7 @@ def test_monomial_subtraction(self): return def test_monomial_multiplication(self): - + # Usual multiplication. # The positive and negative powers of the same variable # should cancel out. @@ -116,7 +118,8 @@ def test_monomial_multiplication(self): self.assertEqual(self.m1 * self.m2, self.m1) # Test usual float multiplication. - self.assertEqual(self.m7 * self.m3, Monomial({1: 4, 2: -1, 7: 2}, -1.5*math.pi)) + self.assertEqual(self.m7 * self.m3, Monomial({1: 4, 2: -1, 7: 2}, + -1.5*math.pi)) return @@ -125,10 +128,11 @@ def test_monomial_inverse(self): # The Zero monomial is not invertible. self.assertRaises(ValueError, lambda x: x.inverse(), self.m1) self.assertRaises(ValueError, lambda x: x.inverse(), self.m8) - self.assertRaises(ValueError, lambda x: x.inverse(), Monomial({},self.m12)) + self.assertRaises(ValueError, lambda x: x.inverse(), + Monomial({}, self.m12)) # Check some inverses. - self.assertEqual(self.m7.inverse(), Monomial({1: -2, 7: -2}, -1/math.pi)) + self.assertEqual(self.m7.inverse(), Monomial({1: -2, 7: -2}, -1 / math.pi)) # Doesn't matter if the coefficient is Fraction or float. # Both should be treated as same. @@ -142,31 +146,41 @@ def test_monomial_inverse(self): def test_monomial_division(self): # Any monomial divided by the Zero Monomial should raise a ValueError. - self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), self.m2, self.m1) - self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), self.m2, self.m8) - self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), self.m2, self.m12) + self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), + self.m2, self.m1) + self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), + self.m2, self.m8) + self.assertRaises(ValueError, lambda x, y: x.__truediv__(y), + self.m2, self.m12) # Test some usual cases. - self.assertEqual(self.m7 / self.m3, Monomial({2: 1, 7: 2}, -2*math.pi/3)) + self.assertEqual(self.m7 / self.m3, Monomial({2: 1, 7: 2}, + -2 * math.pi / 3)) self.assertEqual(self.m14 / self.m13, Monomial({1: 1}) * Fraction(-3, 2)) return def test_monomial_substitution(self): # Test with int. - self.assertAlmostEqual(self.m7.substitute(2), -16*math.pi, delta=1e-9) + self.assertAlmostEqual(self.m7.substitute(2), -16 * math.pi, delta=1e-9) # Test with float. - self.assertAlmostEqual(self.m7.substitute(1.5), (1.5 ** 4)* -math.pi, delta=1e-9) + self.assertAlmostEqual(self.m7.substitute(1.5), (1.5 ** 4) * -math.pi, + delta=1e-9) # Test with Fraction. - self.assertAlmostEqual(self.m7.substitute(Fraction(-1, 2)), (Fraction(-1, 2) ** 4)*-math.pi, delta=1e-9) + self.assertAlmostEqual(self.m7.substitute(Fraction(-1, 2)), + (Fraction(-1, 2) ** 4)*-math.pi, delta=1e-9) # Test with a complete substitution map. - self.assertAlmostEqual(self.m7.substitute({1: 3, 7: 0}), (3 ** 2) * (0 ** 2) * -math.pi, delta=1e-9) + self.assertAlmostEqual(self.m7.substitute({1: 3, 7: 0}), + (3 ** 2) * (0 ** 2) * -math.pi, delta=1e-9) # Test with a more than complete substitution map. - self.assertAlmostEqual(self.m7.substitute({1: 3, 7: 0, 2: 2}), (3 ** 2) * (0 ** 2) * -math.pi, delta=1e-9) - + self.assertAlmostEqual(self.m7.substitute({1: 3, 7: 0, 2: 2}), + (3 ** 2) * (0 ** 2) * -math.pi, delta=1e-9) + # Should raise a ValueError if not enough variables are supplied! - self.assertRaises(ValueError, lambda x, y: x.substitute(y), self.m7, {1: 3, 2: 2}) - self.assertRaises(ValueError, lambda x, y: x.substitute(y), self.m7, {2: 2}) + self.assertRaises(ValueError, lambda x, y: x.substitute(y), self.m7, + {1: 3, 2: 2}) + self.assertRaises(ValueError, lambda x, y: x.substitute(y), self.m7, + {2: 2}) # The zero monomial always gives zero upon substitution. self.assertEqual(self.m8.substitute(2), 0) @@ -193,7 +207,7 @@ def test_monomial_clone(self): # and same coefficient. self.assertEqual(self.m3, self.m3.clone()) - # The zero monomial is identified and + # The zero monomial is identified and # always clones to itself. self.assertEqual(self.m1, self.m8.clone()) self.assertEqual(self.m1, self.m1.clone()) @@ -203,4 +217,4 @@ def test_monomial_clone(self): if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_queues.py b/tests/test_queues.py index b5b49ef61..5a2f4c89d 100644 --- a/tests/test_queues.py +++ b/tests/test_queues.py @@ -80,13 +80,16 @@ def test_max_sliding_window(self): self.assertEqual(max_sliding_window(array, k=7), [6, 7]) array = [8, 5, 10, 7, 9, 4, 15, 12, 90, 13] - self.assertEqual(max_sliding_window(array, k=4), [10, 10, 10, 15, 15, 90, 90]) + self.assertEqual(max_sliding_window(array, k=4), + [10, 10, 10, 15, 15, 90, 90]) self.assertEqual(max_sliding_window(array, k=7), [15, 15, 90, 90]) - self.assertEqual(max_sliding_window(array, k=2), [8, 10, 10, 9, 9, 15, 15, 90, 90]) + self.assertEqual(max_sliding_window(array, k=2), + [8, 10, 10, 9, 9, 15, 15, 90, 90]) def test_reconstruct_queue(self): self.assertEqual([[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]], - reconstruct_queue([[7, 0], [4, 4], [7, 1], [5, 0], [6, 1], [5, 2]])) + reconstruct_queue([[7, 0], [4, 4], [7, 1], [5, 0], + [6, 1], [5, 2]])) class TestPriorityQueue(unittest.TestCase): diff --git a/tests/test_search.py b/tests/test_search.py index d1ea8225d..8f9555048 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -42,7 +42,7 @@ def test_binary_search(self): self.assertEqual(11, binary_search_recur(array, 0, 11, 6)) self.assertEqual(-1, binary_search_recur(array, 0, 11, 7)) self.assertEqual(-1, binary_search_recur(array, 0, 11, -1)) - + def test_ternary_search(self): array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6] self.assertEqual(10, ternary_search(0, 11, 5, array)) @@ -50,7 +50,6 @@ def test_ternary_search(self): self.assertEqual(-1, ternary_search(0, 10, 5, array)) self.assertEqual(-1, ternary_search(0, 11, 7, array)) self.assertEqual(-1, ternary_search(0, 11, -1, array)) - def test_last_occurrence(self): array = [1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6, 6, 6] diff --git a/tests/test_set.py b/tests/test_set.py index 37aea6f2a..e2985c942 100644 --- a/tests/test_set.py +++ b/tests/test_set.py @@ -4,7 +4,9 @@ import unittest + class TestFindKeyboardRow(unittest.TestCase): def test_find_keyboard_row(self): self.assertEqual(["Alaska", "Dad"], - find_keyboard_row(["Hello", "Alaska", "Dad", "Peace"])) + find_keyboard_row(["Hello", "Alaska", + "Dad", "Peace"])) diff --git a/tests/test_sort.py b/tests/test_sort.py index 2c23ab8a5..c80290fdf 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -7,7 +7,6 @@ cycle_sort, exchange_sort, max_heap_sort, min_heap_sort, - insertion_sort, merge_sort, pancake_sort, pigeonhole_sort, @@ -42,7 +41,8 @@ def test_bogo_sort(self): self.assertTrue(is_sorted(bogo_sort([1, 23, 5]))) def test_bitonic_sort(self): - self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) def test_bubble_sort(self): self.assertTrue(is_sorted(bubble_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) @@ -51,36 +51,43 @@ def test_comb_sort(self): self.assertTrue(is_sorted(comb_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_counting_sort(self): - self.assertTrue(is_sorted(counting_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(counting_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) def test_cycle_sort(self): self.assertTrue(is_sorted(cycle_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_exchange_sort(self): - self.assertTrue(is_sorted(exchange_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) - + self.assertTrue(is_sorted(exchange_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) + def test_heap_sort(self): - self.assertTrue(is_sorted(max_heap_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(max_heap_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) - self.assertTrue(is_sorted(min_heap_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(min_heap_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) def test_insertion_sort(self): - self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(bitonic_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) def test_merge_sort(self): self.assertTrue(is_sorted(merge_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_pancake_sort(self): - self.assertTrue(is_sorted(pancake_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) - + self.assertTrue(is_sorted(pancake_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) + def test_pigeonhole_sort(self): self.assertTrue(is_sorted(pigeonhole_sort([1, 5, 65, 23, 57, 1232]))) - + def test_quick_sort(self): self.assertTrue(is_sorted(quick_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_selection_sort(self): - self.assertTrue(is_sorted(selection_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(selection_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) def test_bucket_sort(self): self.assertTrue(is_sorted(bucket_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) @@ -95,24 +102,25 @@ def test_gnome_sort(self): self.assertTrue(is_sorted(gnome_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) def test_cocktail_shaker_sort(self): - self.assertTrue(is_sorted(cocktail_shaker_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + self.assertTrue(is_sorted(cocktail_shaker_sort([1, 3, 2, 5, 65, + 23, 57, 1232]))) class TestTopSort(unittest.TestCase): def setUp(self): self.depGraph = { - "a" : [ "b" ], - "b" : [ "c" ], - "c" : [ 'e'], - 'e' : [ 'g' ], - "d" : [ ], - "f" : ["e" , "d"], - "g" : [ ] + "a": ["b"], + "b": ["c"], + "c": ['e'], + 'e': ['g'], + "d": [], + "f": ["e", "d"], + "g": [] } def test_topsort(self): res = top_sort_recursive(self.depGraph) - #print(res) + # print(res) self.assertTrue(res.index('g') < res.index('e')) res = top_sort(self.depGraph) self.assertTrue(res.index('g') < res.index('e')) diff --git a/tests/test_stack.py b/tests/test_stack.py index 78822bc17..93b389737 100644 --- a/tests/test_stack.py +++ b/tests/test_stack.py @@ -11,6 +11,8 @@ ) import unittest + + class TestSuite(unittest.TestCase): def test_is_consecutive(self): self.assertTrue(first_is_consecutive([3, 4, 5, 6, 7])) @@ -133,6 +135,7 @@ def test_LinkedListStack(self): self.assertTrue(stack.is_empty()) + class TestOrderedStack(unittest.TestCase): def test_OrderedStack(self): stack = OrderedStack() diff --git a/tests/test_streaming.py b/tests/test_streaming.py index 701b5f4ce..2f59827ef 100644 --- a/tests/test_streaming.py +++ b/tests/test_streaming.py @@ -9,22 +9,33 @@ class TestMisraGreis(unittest.TestCase): def test_misra_correct(self): - self.assertEqual({'4':5},misras_gries([1,4,4,4,5,4,4])) - self.assertEqual({'1':4},misras_gries([0,0,0,1,1,1,1])) - self.assertEqual({'0':4,'1':3},misras_gries([0,0,0,0,1,1,1,2,2],3)) - + self.assertEqual({'4': 5}, misras_gries([1, 4, 4, 4, 5, 4, 4])) + self.assertEqual({'1': 4}, misras_gries([0, 0, 0, 1, 1, 1, 1])) + self.assertEqual({'0': 4, '1': 3}, misras_gries([0, 0, 0, 0, 1, 1, + 1, 2, 2], 3)) + def test_misra_incorrect(self): - self.assertEqual(None,misras_gries([1,2,5,4,5,4,4,5,4,4,5])) - self.assertEqual(None,misras_gries([0,0,0,2,1,1,1])) - self.assertEqual(None,misras_gries([0,0,0,1,1,1])) + self.assertEqual(None, misras_gries([1, 2, 5, 4, 5, 4, 4, 5, 4, 4, 5])) + self.assertEqual(None, misras_gries([0, 0, 0, 2, 1, 1, 1])) + self.assertEqual(None, misras_gries([0, 0, 0, 1, 1, 1])) + class TestOneSparse(unittest.TestCase): def test_one_sparse_correct(self): - self.assertEqual(4,one_sparse([(4,'+'), (2,'+'),(2,'-'),(4,'+'),(3,'+'),(3,'-')])) - self.assertEqual(2,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+')])) - + self.assertEqual(4, one_sparse([(4, '+'), (2, '+'), (2, '-'), + (4, '+'), (3, '+'), (3, '-')])) + self.assertEqual(2, one_sparse([(2, '+'), (2, '+'), (2, '+'), + (2, '+'), (2, '+'), (2, '+'), + (2, '+')])) def test_one_sparse_incorrect(self): - self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(1,'+')])) #Two values remaining - self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'-'),(2,'-'),(2,'-'),(2,'-')])) # No values remaining - self.assertEqual(None,one_sparse([(2,'+'),(2,'+'),(4,'+'),(4,'+')])) # Bitsum sum of sign is inccorect + self.assertEqual(None, one_sparse([(2, '+'), (2, '+'), (2, '+'), + (2, '+'), (2, '+'), (2, '+'), + (1, '+')])) # Two values remaining + self.assertEqual(None, one_sparse([(2, '+'), (2, '+'), + (2, '+'), (2, '+'), + (2, '-'), (2, '-'), (2, '-'), + (2, '-')])) # No values remaining + # Bitsum sum of sign is inccorect + self.assertEqual(None, one_sparse([(2, '+'), (2, '+'), + (4, '+'), (4, '+')])) diff --git a/tests/test_strings.py b/tests/test_strings.py index 893498156..ee0d0d207 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -8,7 +8,7 @@ group_anagrams, int_to_roman, is_palindrome, is_palindrome_reverse, - is_palindrome_two_pointer, is_palindrome_stack, is_palindrome_deque, + is_palindrome_two_pointer, is_palindrome_stack, is_palindrome_deque, is_rotated, is_rotated_v1, license_number, make_sentence, @@ -20,9 +20,7 @@ reverse_vowel, reverse_words, roman_to_int, - strip_url_params1, strip_url_params2, strip_url_params3, - is_valid_coordinates_0, is_valid_coordinates_1, - is_valid_coordinates_regular_expression, + is_valid_coordinates_0, word_squares, convert_morse_word, unique_morse, judge_circle, @@ -34,7 +32,8 @@ repeat_string, text_justification, min_distance, - longest_common_prefix_v1, longest_common_prefix_v2, longest_common_prefix_v3, + longest_common_prefix_v1, longest_common_prefix_v2, + longest_common_prefix_v3, rotate, rotate_alt, first_unique_char, repeat_substring, @@ -79,12 +78,17 @@ def test_match_symbol(self): self.assertEqual(self.result, match_symbol(self.words, self.symbols)) def test_match_symbol_1(self): - self.assertEqual(['[Am]azon', 'Mi[cro]soft', 'Goog[le]'], match_symbol_1(self.words, self.symbols)) + self.assertEqual(['[Am]azon', 'Mi[cro]soft', 'Goog[le]'], + match_symbol_1(self.words, self.symbols)) def test_bracket(self): - self.assertEqual(('[Am]azon', 'Mi[cro]soft', 'Goog[le]'), bracket(self.words, self.symbols)) - self.assertEqual(('Amazon', 'Microsoft', 'Google'), bracket(self.words, ['thisshouldnotmatch'])) - self.assertEqual(('Amazon', 'M[i]crosoft', 'Google'), bracket(self.words, ['i', 'i'])) + self.assertEqual(('[Am]azon', 'Mi[cro]soft', 'Goog[le]'), + bracket(self.words, self.symbols)) + self.assertEqual(('Amazon', 'Microsoft', 'Google'), + bracket(self.words, ['thisshouldnotmatch'])) + self.assertEqual(('Amazon', 'M[i]crosoft', 'Google'), + bracket(self.words, ['i', 'i'])) + class TestDecodeString(unittest.TestCase): """[summary] @@ -120,7 +124,8 @@ class TestDomainExtractor(unittest.TestCase): """ def test_valid(self): - self.assertEqual(domain_name_1("https://github.com/SaadBenn"), "github") + self.assertEqual(domain_name_1("https://github.com/SaadBenn"), + "github") def test_invalid(self): self.assertEqual(domain_name_2("http://google.com"), "google") @@ -138,7 +143,8 @@ def test_encode(self): self.assertEqual("4:keon2:is7:awesome", encode("keon is awesome")) def test_decode(self): - self.assertEqual(['keon', 'is', 'awesome'], decode("4:keon2:is7:awesome")) + self.assertEqual(['keon', 'is', 'awesome'], + decode("4:keon2:is7:awesome")) class TestGroupAnagrams(unittest.TestCase): @@ -151,7 +157,8 @@ class TestGroupAnagrams(unittest.TestCase): def test_group_anagrams(self): self.assertEqual([['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']], \ - group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"])) + group_anagrams(["eat", "tea", "tan", "ate", "nat", + "bat"])) class TestIntToRoman(unittest.TestCase): @@ -231,7 +238,7 @@ def test_rotate(self): self.assertEqual("hello", rotate("hello", 5)) self.assertEqual("elloh", rotate("hello", 6)) self.assertEqual("llohe", rotate("hello", 7)) - + def test_rotate_alt(self): self.assertEqual("llohe", rotate_alt("hello", 2)) self.assertEqual("hello", rotate_alt("hello", 5)) @@ -400,14 +407,20 @@ def test_roman_to_int(self): # """ # def test_strip_url_params1(self): -# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") -# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2&a=2"), +# "www.saadbenn.com?a=1&b=2") +# self.assertEqual(strip_url_params1("www.saadbenn.com?a=1&b=2", +# ['b']), "www.saadbenn.com?a=1") # def test_strip_url_params2(self): -# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") -# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2&a=2"), +# "www.saadbenn.com?a=1&b=2") +# self.assertEqual(strip_url_params2("www.saadbenn.com?a=1&b=2", +# 'b']), "www.saadbenn.com?a=1") # def test_strip_url_params3(self): -# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2&a=2"), "www.saadbenn.com?a=1&b=2") -# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2", ['b']), "www.saadbenn.com?a=1") +# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2&a=2"), +# "www.saadbenn.com?a=1&b=2") +# self.assertEqual(strip_url_params3("www.saadbenn.com?a=1&b=2", +# ['b']), "www.saadbenn.com?a=1") class TestValidateCoordinates(unittest.TestCase): @@ -424,7 +437,9 @@ def test_valid(self): self.assertTrue(is_valid_coordinates_0(coordinate)) def test_invalid(self): - invalid_coordinates = ["23.234, - 23.4234", "99.234, 12.324", "6.325624, 43.34345.345", "0, 1,2", "23.245, 1e1"] + invalid_coordinates = ["23.234, - 23.4234", "99.234, 12.324", + "6.325624, 43.34345.345", "0, 1,2", + "23.245, 1e1"] for coordinate in invalid_coordinates: self.assertFalse(is_valid_coordinates_0(coordinate)) @@ -438,8 +453,10 @@ class TestWordSquares(unittest.TestCase): """ def test_word_squares(self): - self.assertEqual([['wall', 'area', 'lead', 'lady'], ['ball', 'area', 'lead', 'lady']], \ - word_squares(["area", "lead", "wall", "lady", "ball"])) + self.assertEqual([['wall', 'area', 'lead', 'lady'], ['ball', 'area', + 'lead', 'lady']], \ + word_squares(["area", "lead", "wall", + "lady", "ball"])) class TestUniqueMorse(unittest.TestCase): @@ -468,6 +485,7 @@ def test_caesar_cipher(self): self.assertEqual("Lipps_Asvph!", caesar_cipher("Hello_World!", 4)) self.assertEqual("okffng-Qwvb", caesar_cipher("middle-Outz", 2)) + class TestCheckPangram(unittest.TestCase): def test_check_pangram(self): self.assertTrue(check_pangram("The quick brown fox jumps over the lazy dog")) @@ -499,47 +517,58 @@ def test_text_justification(self): self.assertEqual(["This is an", "example of text", "justification. "], - - text_justification(["This", "is", "an", "example", "of", "text", "justification."] - , 16) + text_justification(["This", "is", "an", "example", + "of", "text", + "justification."], 16) ) self.assertEqual(["What must be", "acknowledgment ", "shall be "], - - text_justification(["What", "must", "be", "acknowledgment", "shall", "be"] - , 16) + text_justification(["What", "must", "be", + "acknowledgment", "shall", + "be"], 16) ) + class TestMinDistance(unittest.TestCase): def test_min_distance(self): self.assertEqual(2, min_distance("sea", "eat")) self.assertEqual(6, min_distance("abAlgocrithmf", "Algorithmmd")) + class TestLongestCommonPrefix(unittest.TestCase): def test_longest_common_prefix(self): # Test first solution - self.assertEqual("fl", longest_common_prefix_v1(["flower","flow","flight"])) - self.assertEqual("", longest_common_prefix_v1(["dog","racecar","car"])) + self.assertEqual("fl", longest_common_prefix_v1(["flower", "flow", + "flight"])) + self.assertEqual("", longest_common_prefix_v1(["dog", "racecar", + "car"])) # Test second solution - self.assertEqual("fl", longest_common_prefix_v2(["flower","flow","flight"])) - self.assertEqual("", longest_common_prefix_v2(["dog","racecar","car"])) + self.assertEqual("fl", longest_common_prefix_v2(["flower", "flow", + "flight"])) + self.assertEqual("", longest_common_prefix_v2(["dog", "racecar", + "car"])) # Test third solution - self.assertEqual("fl", longest_common_prefix_v3(["flower","flow","flight"])) - self.assertEqual("", longest_common_prefix_v3(["dog","racecar","car"])) + self.assertEqual("fl", longest_common_prefix_v3(["flower", "flow", + "flight"])) + self.assertEqual("", longest_common_prefix_v3(["dog", "racecar", + "car"])) + class TestFirstUniqueChar(unittest.TestCase): def test_first_unique_char(self): self.assertEqual(0, first_unique_char("leetcode")) self.assertEqual(2, first_unique_char("loveleetcode")) + class TestRepeatSubstring(unittest.TestCase): def test_repeat_substring(self): self.assertTrue(repeat_substring("abab")) self.assertFalse(repeat_substring("aba")) self.assertTrue(repeat_substring("abcabcabcabc")) + class TestAtbashCipher(unittest.TestCase): """[summary] Test for the file atbash_cipher.py @@ -555,22 +584,19 @@ def test_atbash_cipher(self): self.assertEqual("ZggzXP zg WzdM", atbash("AttaCK at DawN")) - class TestLongestPalindromicSubstring(unittest.TestCase): """[summary] Test for the file longest_palindromic_substring.py - Arguments: unittest {[type]} -- [description] """ - def test_longest_palindromic_substring(self): self.assertEqual("bb", longest_palindrome("cbbd")) self.assertEqual("abba", longest_palindrome("abba")) self.assertEqual("asdadsa", longest_palindrome("dasdasdasdasdasdadsa")) self.assertEqual("abba", longest_palindrome("cabba")) - + class TestKnuthMorrisPratt(unittest.TestCase): """[summary] Test for the file knuth_morris_pratt.py @@ -585,6 +611,7 @@ def test_knuth_morris_pratt(self): self.assertEqual([0, 4], knuth_morris_pratt("abcdabc", "abc")) self.assertEqual([], knuth_morris_pratt("aabcdaab", "aba")) + class TestPanagram(unittest.TestCase): """[summary] Test for the file panagram.py @@ -663,33 +690,34 @@ def test_swedish_panagram(self): # Assert self.assertEqual(True, res) + class TestFizzbuzz(unittest.TestCase): """[summary] Tests for the fizzbuzz method in file fizzbuzz.py """ - def test_fizzbuzz(self): - # Testing that n < 0 returns a Value Error - self.assertRaises(ValueError, fizzbuzz.fizzbuzz, -2) - - # Testing that a string returns a Type Error. - self.assertRaises(TypeError, fizzbuzz.fizzbuzz, "hello") - - # Testing a base case, n = 3 - result = fizzbuzz.fizzbuzz(3) - expected = [1, 2, "Fizz"] - self.assertEqual(result, expected) - - # Testing a base case, n = 5 - result = fizzbuzz.fizzbuzz(5) - expected = [1, 2, "Fizz", 4, "Buzz"] - self.assertEqual(result, expected) - - # Testing a base case, n = 15 i.e. mod 3 and 5 - result = fizzbuzz.fizzbuzz(15) - expected = [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, - "Fizz", 13, 14, "FizzBuzz"] - self.assertEqual(result, expected) - + # Testing that n < 0 returns a Value Error + self.assertRaises(ValueError, fizzbuzz.fizzbuzz, -2) + + # Testing that a string returns a Type Error. + self.assertRaises(TypeError, fizzbuzz.fizzbuzz, "hello") + + # Testing a base case, n = 3 + result = fizzbuzz.fizzbuzz(3) + expected = [1, 2, "Fizz"] + self.assertEqual(result, expected) + + # Testing a base case, n = 5 + result = fizzbuzz.fizzbuzz(5) + expected = [1, 2, "Fizz", 4, "Buzz"] + self.assertEqual(result, expected) + + # Testing a base case, n = 15 i.e. mod 3 and 5 + result = fizzbuzz.fizzbuzz(15) + expected = [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, + "Fizz", 13, 14, "FizzBuzz"] + self.assertEqual(result, expected) + + if __name__ == "__main__": unittest.main() diff --git a/tests/test_tree.py b/tests/test_tree.py index 170a931dd..c9d0f0fd4 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -65,7 +65,8 @@ def setUpClass(cls): cls.range = 10000 def setUp(self): - self.keys_to_insert = [self.random.randrange(-self.range, self.range) for i in range(self.range)] + self.keys_to_insert = [self.random.randrange(-self.range, self.range) + for i in range(self.range)] def test_insertion_and_find_even_degree(self): btree = BTree(4) @@ -111,16 +112,18 @@ def test_deletion_odd_degree(self): self.assertEqual(btree.root.keys, []) self.assertEqual(btree.root.children, []) + class TestConstructTreePreorderPostorder(unittest.TestCase): def test_construct_tree(self): - + # Test 1 ctpp.pre_index = 0 pre1 = [1, 2, 4, 8, 9, 5, 3, 6, 7] post1 = [8, 9, 4, 5, 2, 6, 7, 3, 1] size1 = len(pre1) - self.assertEqual(ctpp.construct_tree(pre1, post1, size1), [8,4,9,2,5,1,6,3,7]) + self.assertEqual(ctpp.construct_tree(pre1, post1, size1), + [8, 4, 9, 2, 5, 1, 6, 3, 7]) # Test 2 ctpp.pre_index = 0 @@ -128,7 +131,8 @@ def test_construct_tree(self): post2 = [4, 5, 2, 6, 7, 3, 1] size2 = len(pre2) - self.assertEqual(ctpp.construct_tree(pre2, post2, size2), [4,2,5,1,6,3,7]) + self.assertEqual(ctpp.construct_tree(pre2, post2, size2), + [4, 2, 5, 1, 6, 3, 7]) # Test 3 ctpp.pre_index = 0 @@ -136,7 +140,8 @@ def test_construct_tree(self): post3 = [16, 21, 7, 1, 9, 5, 12] size3 = len(pre3) - self.assertEqual(ctpp.construct_tree(pre3, post3, size3), [16,7,21,12,1,5,9]) + self.assertEqual(ctpp.construct_tree(pre3, post3, size3), + [16, 7, 21, 12, 1, 5, 9]) class TestFenwickTree(unittest.TestCase): @@ -170,5 +175,6 @@ def test_construct_tree_with_update_3(self): ft.update_bit(bit_tree, 2, 11) self.assertEqual(23, ft.get_sum(bit_tree, 4)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_unix.py b/tests/test_unix.py index e7a6c6349..3cafba98f 100644 --- a/tests/test_unix.py +++ b/tests/test_unix.py @@ -6,12 +6,18 @@ ) import os import unittest + + class TestUnixPath(unittest.TestCase): def test_join_with_slash(self): - self.assertEqual("path/to/dir/file", join_with_slash("path/to/dir/", "file")) - self.assertEqual("path/to/dir/file", join_with_slash("path/to/dir", "file")) - self.assertEqual("http://algorithms/part", join_with_slash("http://algorithms", "part")) - self.assertEqual("http://algorithms/part", join_with_slash("http://algorithms/", "part")) + self.assertEqual("path/to/dir/file", + join_with_slash("path/to/dir/", "file")) + self.assertEqual("path/to/dir/file", + join_with_slash("path/to/dir", "file")) + self.assertEqual("http://algorithms/part", + join_with_slash("http://algorithms", "part")) + self.assertEqual("http://algorithms/part", + join_with_slash("http://algorithms/", "part")) def test_full_path(self): file_name = "file_name" From 8149be50969a3ef587d938f029c5bc56169493bf Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 2 Mar 2022 05:14:02 +0100 Subject: [PATCH 278/302] [Documentation] knuth_morris_pratt (#835) * attach documentation to method; add annotations * add test case for list of integers Co-authored-by: Pieter Eendebak --- algorithms/strings/knuth_morris_pratt.py | 28 ++++++++++++++++-------- tests/test_strings.py | 1 + 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/algorithms/strings/knuth_morris_pratt.py b/algorithms/strings/knuth_morris_pratt.py index 0bdf4d550..e1953a218 100644 --- a/algorithms/strings/knuth_morris_pratt.py +++ b/algorithms/strings/knuth_morris_pratt.py @@ -1,13 +1,23 @@ -""" -Given two strings text and pattern, -return the list of start indexes in text that matches with the pattern -using knuth_morris_pratt algorithm. -If idx is in the list, text[idx : idx + M] matches with pattern. -Time complexity : O(N+M) -N and M is the length of text and pattern, respectively. -""" +from typing import Sequence, List -def knuth_morris_pratt(text, pattern): +def knuth_morris_pratt(text : Sequence, pattern : Sequence) -> List[int]: + """ + Given two strings text and pattern, return the list of start indexes in text that matches with the pattern + using knuth_morris_pratt algorithm. + + Args: + text: Text to search + pattern: Pattern to search in the text + Returns: + List of indices of patterns found + + Example: + >>> knuth_morris_pratt('hello there hero!', 'he') + [0, 7, 12] + + If idx is in the list, text[idx : idx + M] matches with pattern. + Time complexity of the algorithm is O(N+M), with N and M the length of text and pattern, respectively. + """ n = len(text) m = len(pattern) pi = [0 for i in range(m)] diff --git a/tests/test_strings.py b/tests/test_strings.py index ee0d0d207..57f5ff0c1 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -610,6 +610,7 @@ def test_knuth_morris_pratt(self): self.assertEqual([0, 1, 2, 3, 4], knuth_morris_pratt("aaaaaaa", "aaa")) self.assertEqual([0, 4], knuth_morris_pratt("abcdabc", "abc")) self.assertEqual([], knuth_morris_pratt("aabcdaab", "aba")) + self.assertEqual([0, 4], knuth_morris_pratt([0,0,1,1,0,0,1,0], [0,0])) class TestPanagram(unittest.TestCase): From 15e5292d21f1fde70a4cdb428c25db0192b5b7f0 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 2 Mar 2022 17:48:34 +0530 Subject: [PATCH 279/302] Fix flake8 issues (#837) --- algorithms/compression/elias.py | 26 +++-- algorithms/dp/coin_change.py | 21 ++-- algorithms/dp/edit_distance.py | 31 +++-- algorithms/dp/egg_drop.py | 33 +++--- algorithms/dp/fib.py | 21 ++-- algorithms/dp/hosoya_triangle.py | 42 +++---- algorithms/dp/job_scheduling.py | 39 ++++--- algorithms/dp/k_factor.py | 108 ++++++++++-------- algorithms/dp/longest_increasing.py | 53 +++++---- algorithms/dp/matrix_chain_order.py | 39 ++++--- algorithms/dp/min_cost_path.py | 34 +++--- algorithms/dp/planting_trees.py | 22 ++-- .../path_between_two_vertices_in_digraph.py | 41 +++---- .../maths/diffie_hellman_key_exchange.py | 45 ++++---- algorithms/maths/polynomial.py | 8 +- .../maths/symmetry_group_cycle_index.py | 108 +++++++++--------- algorithms/matrix/bomb_enemy.py | 25 ++-- .../matrix/cholesky_matrix_decomposition.py | 9 +- algorithms/matrix/copy_transform.py | 4 + .../matrix/crout_matrix_decomposition.py | 3 +- algorithms/matrix/matrix_exponentiation.py | 6 +- algorithms/matrix/rotate_image.py | 6 +- algorithms/matrix/search_in_sorted_matrix.py | 6 +- algorithms/matrix/sort_matrix_diagonally.py | 2 +- algorithms/matrix/sparse_dot_vector.py | 3 +- algorithms/matrix/sparse_mul.py | 25 ++-- algorithms/matrix/sudoku_validator.py | 15 ++- algorithms/matrix/sum_sub_squares.py | 19 ++- algorithms/queues/max_sliding_window.py | 2 + algorithms/queues/priority_queue.py | 1 - algorithms/queues/queue.py | 3 + algorithms/queues/zigzagiterator.py | 13 ++- algorithms/set/find_keyboard_row.py | 1 + algorithms/stack/is_consecutive.py | 10 +- algorithms/stack/is_sorted.py | 2 + algorithms/stack/longest_abs_path.py | 66 +++++------ algorithms/stack/ordered_stack.py | 65 ++++++----- algorithms/stack/remove_min.py | 2 + algorithms/stack/simplify_path.py | 5 +- algorithms/stack/stack.py | 2 + algorithms/stack/stutter.py | 2 + algorithms/stack/switch_pairs.py | 8 +- algorithms/stack/valid_parenthesis.py | 2 + tests/test_iterative_segment_tree.py | 2 +- 44 files changed, 548 insertions(+), 432 deletions(-) diff --git a/algorithms/compression/elias.py b/algorithms/compression/elias.py index bdeb7fd39..974fc3772 100644 --- a/algorithms/compression/elias.py +++ b/algorithms/compression/elias.py @@ -1,17 +1,20 @@ """ -Elias γ code or Elias gamma code is a universal code encoding positive integers. -It is used most commonly when coding integers whose upper-bound cannot be determined beforehand. -Elias δ code or Elias delta code is a universal code encoding the positive integers, +Elias γ code or Elias gamma code is a universal code +encoding positive integers. +It is used most commonly when coding integers whose +upper-bound cannot be determined beforehand. +Elias δ code or Elias delta code is a universal code + encoding the positive integers, that includes Elias γ code when calculating. Both were developed by Peter Elias. """ -from math import log,ceil +from math import log -log2 = lambda x: log(x,2) +log2 = lambda x: log(x, 2) # Calculates the binary number -def binary(x,l=1): +def binary(x, l=1): fmt = '{0:0%db}' % l return fmt.format(x) @@ -21,12 +24,13 @@ def unary(x): def elias_generic(lencoding, x): """ - The compressed data is calculated in two parts. - The first part is the unary number of 1 + ⌊log2(x)⌋. + The compressed data is calculated in two parts. + The first part is the unary number of 1 + ⌊log2(x)⌋. The second part is the binary number of x - 2^(⌊log2(x)⌋). For the final result we add these two parts. """ - if x == 0: return '0' + if x == 0: + return '0' first_part = 1 + int(log2(x)) @@ -34,7 +38,7 @@ def elias_generic(lencoding, x): k = int(log2(x)) - return lencoding(first_part) + binary(a,k) + return lencoding(first_part) + binary(a, k) def elias_gamma(x): """ @@ -46,4 +50,4 @@ def elias_delta(x): """ For the first part we put the elias_g of the number. """ - return elias_generic(elias_gamma,x) + return elias_generic(elias_gamma, x) diff --git a/algorithms/dp/coin_change.py b/algorithms/dp/coin_change.py index e9a83fcbf..a1d739d9b 100644 --- a/algorithms/dp/coin_change.py +++ b/algorithms/dp/coin_change.py @@ -1,28 +1,31 @@ """ Problem -Given a value n, if we want to make change for N cents, and we have infinite supply of each of -coins = {S1, S2, .. , Sm} valued coins, how many ways can we make the change? +Given a value n, if we want to make change for N cents, +and we have infinite supply of each of +coins = {S1, S2, .. , Sm} valued coins, how many ways +can we make the change? The order of coins doesn't matter. -For example, for n = 4 and coins = [1, 2, 3], there are four solutions: -[1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3]. -So output should be 4. +For example, for n = 4 and coins = [1, 2, 3], there are +four solutions: +[1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3]. +So output should be 4. -For n = 10 and coins = [2, 5, 3, 6], there are five solutions: -[2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]. +For n = 10 and coins = [2, 5, 3, 6], there are five solutions: +[2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]. So the output should be 5. Time complexity: O(n * m) where n is the value and m is the number of coins Space complexity: O(n) """ + def count(coins, n): # initialize dp array and set base case as 1 dp = [1] + [0] * n - + # fill dp in a bottom up manner for coin in coins: for i in range(coin, n+1): dp[i] += dp[i-coin] return dp[n] - diff --git a/algorithms/dp/edit_distance.py b/algorithms/dp/edit_distance.py index ecf6beb06..c21c766b7 100644 --- a/algorithms/dp/edit_distance.py +++ b/algorithms/dp/edit_distance.py @@ -1,34 +1,43 @@ -"""The edit distance between two words is the minimum number of letter insertions, -letter deletions, and letter substitutions required to transform one word into another. +"""The edit distance between two words is the minimum number +of letter insertions, letter deletions, and letter substitutions +required to transform one word into another. -For example, the edit distance between FOOD and MONEY is at most four: +For example, the edit distance between FOOD and MONEY is at +most four: FOOD -> MOOD -> MOND -> MONED -> MONEY -Given two words A and B, find the minimum number of operations required to transform one string into the other. +Given two words A and B, find the minimum number of operations +required to transform one string into the other. In other words, find the edit distance between A and B. Thought process: -Let edit(i, j) denote the edit distance between the prefixes A[1..i] and B[1..j]. +Let edit(i, j) denote the edit distance between +the prefixes A[1..i] and B[1..j]. Then, the function satifies the following recurrence: edit(i, j) = i if j = 0 j if i = 0 - min(edit(i-1, j) + 1, + min(edit(i-1, j) + 1, edit(i, j-1), + 1, edit(i-1, j-1) + cost) otherwise -There are two base cases, both of which occur when one string is empty and the other is not. -1. To convert an empty string A into a string B of length n, perform n insertions. -2. To convert a string A of length m into an empty string B, perform m deletions. +There are two base cases, both of which occur when one string is empty +and the other is not. +1. To convert an empty string A into a string B of length n, +perform n insertions. +2. To convert a string A of length m into an empty string B, +perform m deletions. Here, the cost is 1 if a substitution is required, -or 0 if both chars in words A and B are the same at indexes i and j, respectively. +or 0 if both chars in words A and B are the same at +indexes i and j, respectively. To find the edit distance between two words A and B, -we need to find edit(m, n), where m is the length of A and n is the length of B. +we need to find edit(m, n), where m is the length of A and n +is the length of B. """ diff --git a/algorithms/dp/egg_drop.py b/algorithms/dp/egg_drop.py index d07bee872..b9d38508a 100644 --- a/algorithms/dp/egg_drop.py +++ b/algorithms/dp/egg_drop.py @@ -1,21 +1,21 @@ """ -You are given K eggs, and you have access to a building with N floors -from 1 to N. Each egg is identical in function, and if an egg breaks, -you cannot drop it again. You know that there exists a floor F with -0 <= F <= N such that any egg dropped at a floor higher than F will -break, and any egg dropped at or below floor F will not break. -Each move, you may take an egg (if you have an unbroken one) and drop -it from any floor X (with 1 <= X <= N). Your goal is to know with -certainty what the value of F is. What is the minimum number of moves -that you need to know with certainty what F is, regardless of the +You are given K eggs, and you have access to a building with N floors +from 1 to N. Each egg is identical in function, and if an egg breaks, +you cannot drop it again. You know that there exists a floor F with +0 <= F <= N such that any egg dropped at a floor higher than F will +break, and any egg dropped at or below floor F will not break. +Each move, you may take an egg (if you have an unbroken one) and drop +it from any floor X (with 1 <= X <= N). Your goal is to know with +certainty what the value of F is. What is the minimum number of moves +that you need to know with certainty what F is, regardless of the initial value of F? Example: Input: K = 1, N = 2 Output: 2 -Explanation: +Explanation: Drop the egg from floor 1. If it breaks, we know with certainty that F = 0. -Otherwise, drop the egg from floor 2. If it breaks, we know with +Otherwise, drop the egg from floor 2. If it breaks, we know with certainty that F = 1. If it didn't break, then we know with certainty F = 2. Hence, we needed 2 moves in the worst case to know what F is with certainty. @@ -24,20 +24,21 @@ # A Dynamic Programming based Python Program for the Egg Dropping Puzzle INT_MAX = 32767 + def egg_drop(n, k): # A 2D table where entery eggFloor[i][j] will represent minimum # number of trials needed for i eggs and j floors. - egg_floor = [[0 for x in range(k+1)] for x in range(n+1)] - + egg_floor = [[0 for x in range(k+1)] for x in range(n + 1)] + # We need one trial for one floor and 0 trials for 0 floors for i in range(1, n+1): egg_floor[i][1] = 1 egg_floor[i][0] = 0 - + # We always need j trials for one egg and j floors. for j in range(1, k+1): egg_floor[1][j] = j - + # Fill rest of the entries in table using optimal substructure # property for i in range(2, n+1): @@ -47,6 +48,6 @@ def egg_drop(n, k): res = 1 + max(egg_floor[i-1][x-1], egg_floor[i][j-x]) if res < egg_floor[i][j]: egg_floor[i][j] = res - + # eggFloor[n][k] holds the result return egg_floor[n][k] diff --git a/algorithms/dp/fib.py b/algorithms/dp/fib.py index 7a6fd7140..f51020b74 100644 --- a/algorithms/dp/fib.py +++ b/algorithms/dp/fib.py @@ -1,6 +1,8 @@ ''' -In mathematics, the Fibonacci numbers, commonly denoted Fn, form a sequence, called the Fibonacci sequence, -such that each number is the sum of the two preceding ones, starting from 0 and 1. +In mathematics, the Fibonacci numbers, commonly denoted Fn, +form a sequence, called the Fibonacci sequence, +such that each number is the sum of the two preceding ones, +starting from 0 and 1. That is, F0=0 , F1=1 and @@ -8,10 +10,13 @@ The Fibonacci numbers are the numbers in the following integer sequence. 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……. -In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation +In mathematical terms, the sequence Fn of Fibonacci numbers is +defined by the recurrence relation Here, given a number n, print n-th Fibonacci Number. ''' + + def fib_recursive(n): """[summary] Computes the n-th fibonacci number recursive. @@ -20,7 +25,7 @@ def fib_recursive(n): Arguments: n {[int]} -- [description] - + Returns: [int] -- [description] """ @@ -35,15 +40,16 @@ def fib_recursive(n): # print(fib_recursive(35)) # => 9227465 (slow) + def fib_list(n): """[summary] This algorithm computes the n-th fibbonacci number very quick. approximate O(n) The algorithm use dynamic programming. - + Arguments: n {[int]} -- [description] - + Returns: [int] -- [description] """ @@ -58,13 +64,14 @@ def fib_list(n): # print(fib_list(100)) # => 354224848179261915075 + def fib_iter(n): """[summary] Works iterative approximate O(n) Arguments: n {[int]} -- [description] - + Returns: [int] -- [description] """ diff --git a/algorithms/dp/hosoya_triangle.py b/algorithms/dp/hosoya_triangle.py index 9bf9437ec..d2e1a8587 100644 --- a/algorithms/dp/hosoya_triangle.py +++ b/algorithms/dp/hosoya_triangle.py @@ -8,11 +8,11 @@ For example: printHosoya( 6 ) would return: -1 -1 1 -2 1 2 -3 2 2 3 -5 3 4 3 5 +1 +1 1 +2 1 2 +3 2 2 3 +5 3 4 3 5 8 5 6 6 5 8 The complexity is O(n^3). @@ -20,26 +20,28 @@ """ -def hosoya(n, m): +def hosoya(n, m): if ((n == 0 and m == 0) or (n == 1 and m == 0) or - (n == 1 and m == 1) or (n == 2 and m == 1)): + (n == 1 and m == 1) or (n == 2 and m == 1)): return 1 - if n > m: - return hosoya(n - 1, m) + hosoya(n - 2, m) - elif m == n: - return hosoya(n - 1, m - 1) + hosoya(n - 2, m - 2) - else: + if n > m: + return hosoya(n - 1, m) + hosoya(n - 2, m) + elif m == n: + return hosoya(n - 1, m - 1) + hosoya(n - 2, m - 2) + else: return 0 - -def print_hosoya(n): - for i in range(n): - for j in range(i + 1): - print(hosoya(i, j) , end = " ") - print ("\n", end = "") + + +def print_hosoya(n): + for i in range(n): + for j in range(i + 1): + print(hosoya(i, j), end=" ") + print("\n", end="") + def hosoya_testing(n): x = [] - for i in range(n): - for j in range(i + 1): + for i in range(n): + for j in range(i + 1): x.append(hosoya(i, j)) return x diff --git a/algorithms/dp/job_scheduling.py b/algorithms/dp/job_scheduling.py index eaf98ec44..f1a92f584 100644 --- a/algorithms/dp/job_scheduling.py +++ b/algorithms/dp/job_scheduling.py @@ -1,14 +1,16 @@ -# Python program for weighted job scheduling using Dynamic +# Python program for weighted job scheduling using Dynamic # Programming and Binary Search - + # Class to represent a job + + class Job: def __init__(self, start, finish, profit): - self.start = start + self.start = start self.finish = finish - self.profit = profit - - + self.profit = profit + + # A Binary Search based function to find the latest job # (before current job) that doesn't conflict with current # job. "index" is index of the current job. This function @@ -16,11 +18,11 @@ def __init__(self, start, finish, profit): # The array jobs[] is sorted in increasing order of finish # time. def binary_search(job, start_index): - + # Initialize 'lo' and 'hi' for Binary Search lo = 0 hi = start_index - 1 - + # Perform binary Search iteratively while lo <= hi: mid = (lo + hi) // 2 @@ -32,31 +34,32 @@ def binary_search(job, start_index): else: hi = mid - 1 return -1 - + + # The main function that returns the maximum possible # profit from given array of jobs def schedule(job): - + # Sort jobs according to finish time - job = sorted(job, key = lambda j: j.finish) - + job = sorted(job, key=lambda j: j.finish) + # Create an array to store solutions of subproblems. table[i] # stores the profit for jobs till arr[i] (including arr[i]) - n = len(job) + n = len(job) table = [0 for _ in range(n)] - + table[0] = job[0].profit - + # Fill entries in table[] using recursive property for i in range(1, n): - + # Find profit including the current job incl_prof = job[i].profit l = binary_search(job, i) if (l != -1): incl_prof += table[l] - + # Store maximum of including and excluding table[i] = max(incl_prof, table[i - 1]) - + return table[n-1] diff --git a/algorithms/dp/k_factor.py b/algorithms/dp/k_factor.py index 2fd23d18b..998d825ee 100644 --- a/algorithms/dp/k_factor.py +++ b/algorithms/dp/k_factor.py @@ -1,14 +1,24 @@ -'''The K factor of a string is defined as the number of times 'abba' appears as a substring. -Given two numbers N and k,​ find the number of strings of length N with 'K factor' = k. +'''The K factor of a string is defined as the number of +times 'abba' appears as a substring. + +Given two numbers N and k, find the number of strings of +length N with 'K factor' = k. The algorithms is as follows: -dp[n][k] will be a 4 element array, wherein each element can be the number of strings of length n and 'K factor' = k which belong to the criteria represented by that index: +dp[n][k] will be a 4 element array, wherein each element can be +the number of strings of length n and 'K factor' = k which +belong to the criteria represented by that index: - dp[n][k][0] can be the number of strings of length n and K-factor = k which end with substring 'a' - dp[n][k][1] can be the number of strings of length n and K-factor = k which end with substring 'ab' - dp[n][k][2] can be the number of strings of length n and K-factor = k which end with substring 'abb' - dp[n][k][3] can be the number of strings of length n and K-factor = k which end with anything other than the above substrings (anything other than 'a' 'ab' 'abb') + dp[n][k][0] can be the number of strings of length n and K-factor = k + which end with substring 'a' + dp[n][k][1] can be the number of strings of length n and K-factor = k + which end with substring 'ab' + dp[n][k][2] can be the number of strings of length n and K-factor = k + which end with substring 'abb' + dp[n][k][3] can be the number of strings of length n and K-factor = k + which end with anything other than the above substrings (anything other + than 'a' 'ab' 'abb') Example inputs @@ -18,51 +28,51 @@ ''' -def find_k_factor(n,k): - dp=[[[0 for i in range(4)]for j in range((n-1)//3+2)]for k in range(n+1)] - if(3*k+1>n): + +def find_k_factor(n, k): + dp = [[[0 for i in range(4)]for j in range((n-1)//3+2)]for k in range(n+1)] + if(3*k+1 > n): return 0 - #base cases - dp[1][0][0]=1; - dp[1][0][1]=0; - dp[1][0][2]=0; - dp[1][0][3]=25; + # base cases + dp[1][0][0] = 1 + dp[1][0][1] = 0 + dp[1][0][2] = 0 + dp[1][0][3] = 25 - for i in range(2,n+1): + for i in range(2, n+1): for j in range((n-1)//3+2): - if(j==0): - #adding a at the end - dp[i][j][0]=dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][j][3] - - #adding b at the end - dp[i][j][1]=dp[i-1][j][0] - dp[i][j][2]=dp[i-1][j][1] - - #adding any other lowercase character - dp[i][j][3]=dp[i-1][j][0]*24+dp[i-1][j][1]*24+dp[i-1][j][2]*25+dp[i-1][j][3]*25 - - elif(3*j+1>1 + mid = (l+r) >> 1 if i <= mid: - update(p<<1, l, mid, i, v) + update(p << 1, l, mid, i, v) else: - update((p<<1)|1, mid+1, r, i, v) - tree[p] = max(tree[p<<1], tree[(p<<1)|1]) + update((p << 1) | 1, mid + 1, r, i, v) + tree[p] = max(tree[p << 1], tree[(p << 1) | 1]) def get_max(p, l, r, s, e): if l > e or r < s: return 0 if l >= s and r <= e: return tree[p] - mid = (l+r)>>1 - return max(get_max(p<<1, l, mid, s, e), get_max((p<<1)|1, mid+1, r, s, e)) + mid = (l+r) >> 1 + return max(get_max(p << 1, l, mid, s, e), get_max((p << 1) | 1, mid+1, r, s, e)) ans = 0 for x in sequence: - cur = get_max(1, 0, mx, 0, x-1)+1 - ans = max(ans, cur) - update(1, 0, mx, x, cur) + cur = get_max(1, 0, mx, 0, x-1)+1 + ans = max(ans, cur) + update(1, 0, mx, x, cur) return ans + def longest_increasing_subsequence_optimized2(sequence): """ Optimized dynamic programming algorithm for @@ -81,31 +86,31 @@ def longest_increasing_subsequence_optimized2(sequence): rtype: int """ n = len(sequence) - tree = [0] * (n<<2) + tree = [0] * (n << 2) sorted_seq = sorted((x, -i) for i, x in enumerate(sequence)) + def update(p, l, r, i, v): - if l ==r: + if l == r: tree[p] = v return - mid = (l+r)>>1 + mid = (l+r) >> 1 if i <= mid: - update(p<<1, l, mid, i, v) + update(p << 1, l, mid, i, v) else: - update((p<<1)|1, mid+1, r, i, v) - tree[p] = max(tree[p<<1], tree[(p<<1)|1]) + update((p << 1) | 1, mid+1, r, i, v) + tree[p] = max(tree[p << 1], tree[(p << 1) | 1]) def get_max(p, l, r, s, e): if l > e or r < s: return 0 if l >= s and r <= e: return tree[p] - mid = (l+r)>>1 - return max(get_max(p<<1, l, mid, s, e), get_max((p<<1)|1, mid+1, r, s, e)) + mid = (l+r) >> 1 + return max(get_max(p << 1, l, mid, s, e), get_max((p << 1) | 1, mid+1, r, s, e)) ans = 0 for x, j in sorted_seq: i = -j cur = get_max(1, 0, n-1, 0, i-1)+1 ans = max(ans, cur) update(1, 0, n-1, i, cur) - return ans - + return ans diff --git a/algorithms/dp/matrix_chain_order.py b/algorithms/dp/matrix_chain_order.py index 8c1ecae43..47386f66f 100644 --- a/algorithms/dp/matrix_chain_order.py +++ b/algorithms/dp/matrix_chain_order.py @@ -6,12 +6,13 @@ ''' INF = float("inf") + def matrix_chain_order(array): - n=len(array) + n = len(array) matrix = [[0 for x in range(n)] for x in range(n)] sol = [[0 for x in range(n)] for x in range(n)] - for chain_length in range(2,n): - for a in range(1,n-chain_length+1): + for chain_length in range(2, n): + for a in range(1, n-chain_length+1): b = a+chain_length-1 matrix[a][b] = INF @@ -20,26 +21,30 @@ def matrix_chain_order(array): if cost < matrix[a][b]: matrix[a][b] = cost sol[a][b] = c - return matrix , sol -#Print order of matrix with Ai as matrix + return matrix, sol +# Print order of matrix with Ai as matrix + -def print_optimal_solution(optimal_solution,i,j): - if i==j: - print("A" + str(i),end = " ") +def print_optimal_solution(optimal_solution, i, j): + if i == j: + print("A" + str(i), end=" ") else: - print("(",end = " ") - print_optimal_solution(optimal_solution,i,optimal_solution[i][j]) - print_optimal_solution(optimal_solution,optimal_solution[i][j]+1,j) - print(")",end = " ") + print("(", end=" ") + print_optimal_solution(optimal_solution, i, optimal_solution[i][j]) + print_optimal_solution(optimal_solution, optimal_solution[i][j]+1, j) + print(")", end=" ") + def main(): - array=[30,35,15,5,10,20,25] - n=len(array) - #Size of matrix created from above array will be + array = [30, 35, 15, 5, 10, 20, 25] + n = len(array) + # Size of matrix created from above array will be # 30*35 35*15 15*5 5*10 10*20 20*25 - matrix , optimal_solution = matrix_chain_order(array) + matrix, optimal_solution = matrix_chain_order(array) print("No. of Operation required: "+str((matrix[1][n-1]))) - print_optimal_solution(optimal_solution,1,n-1) + print_optimal_solution(optimal_solution, 1, n-1) + + if __name__ == '__main__': main() diff --git a/algorithms/dp/min_cost_path.py b/algorithms/dp/min_cost_path.py index 8af947075..356489e9a 100644 --- a/algorithms/dp/min_cost_path.py +++ b/algorithms/dp/min_cost_path.py @@ -1,7 +1,7 @@ """ author @goswami-rahul -To find minimum cost path +To find minimum cost path from station 0 to station N-1, where cost of moving from ith station to jth station is given as: @@ -9,11 +9,11 @@ where Matrix[i][j] denotes the cost of moving from station i --> station j for i < j -NOTE that values where Matrix[i][j] and i > j does not +NOTE that values where Matrix[i][j] and i > j does not mean anything, and hence represented by -1 or INF -For the input below (cost matrix), -Minimum cost is obtained as from { 0 --> 1 --> 3} +For the input below (cost matrix), +Minimum cost is obtained as from { 0 --> 1 --> 3} = cost[0][1] + cost[1][3] = 65 the Output will be: @@ -21,33 +21,35 @@ Time Complexity: O(n^2) Space Complexity: O(n) -""" +""" INF = float("inf") + def min_cost(cost): - + n = len(cost) # dist[i] stores minimum cost from 0 --> i. dist = [INF] * n dist[0] = 0 # cost from 0 --> 0 is zero. - + for i in range(n): - for j in range(i+1,n): + for j in range(i+1, n): dist[j] = min(dist[j], dist[i] + cost[i][j]) - + return dist[n-1] + if __name__ == '__main__': - - cost = [ [ 0, 15, 80, 90], # cost[i][j] is the cost of - [-1, 0, 40, 50], # going from i --> j - [-1, -1, 0, 70], - [-1, -1, -1, 0] ] # cost[i][j] = -1 for i > j + + cost = [[0, 15, 80, 90], # cost[i][j] is the cost of + [-1, 0, 40, 50], # going from i --> j + [-1, -1, 0, 70], + [-1, -1, -1, 0]] # cost[i][j] = -1 for i > j total_len = len(cost) - + mcost = min_cost(cost) assert mcost == 65 - + print("The Minimum cost to reach station %d is %d" % (total_len, mcost)) diff --git a/algorithms/dp/planting_trees.py b/algorithms/dp/planting_trees.py index c1efd4e64..56b99cde7 100644 --- a/algorithms/dp/planting_trees.py +++ b/algorithms/dp/planting_trees.py @@ -1,20 +1,24 @@ """ -An even number of trees are left along one side of a country road. You've been assigned the job to -plant these trees at an even interval on both sides of the road. The length L and width W of the road -are variable, and a pair of trees must be planted at the beginning (at 0) and at the end (at L) of -the road. Only one tree can be moved at a time. The goal is to calculate the lowest amount of -distance that the trees have to be moved before they are all in a valid position. +An even number of trees are left along one side of a country road. +You've been assigned the job to plant these trees at an even interval on +both sides of the road. The length L and width W of the road are variable, +and a pair of trees must be planted at the beginning (at 0) +and at the end (at L) of the road. Only one tree can be moved at a time. +The goal is to calculate the lowest amount of distance that the trees +have to be moved before they are all in a valid position. """ from math import sqrt -import sys + def planting_trees(trees, L, W): """ - Returns the minimum distance that trees have to be moved before they are all in a valid state. + Returns the minimum distance that trees have to be moved before they + are all in a valid state. Parameters: - tree (list): A sorted list of integers with all trees' position along the road. + tree (list): A sorted list of integers with all trees' + position along the road. L (int): An integer with the length of the road. W (int): An integer with the width of the road. @@ -42,4 +46,4 @@ def planting_trees(trees, L, W): cmatrix[ri][li-1] + abs(trees[li + ri]-target_locations[li-1]) ) - return cmatrix[n_pairs][n_pairs] \ No newline at end of file + return cmatrix[n_pairs][n_pairs] diff --git a/algorithms/graph/path_between_two_vertices_in_digraph.py b/algorithms/graph/path_between_two_vertices_in_digraph.py index ee6ac418f..f85513320 100644 --- a/algorithms/graph/path_between_two_vertices_in_digraph.py +++ b/algorithms/graph/path_between_two_vertices_in_digraph.py @@ -1,30 +1,31 @@ from collections import defaultdict + class Graph: - def __init__(self,v): + def __init__(self, v): self.v = v self.graph = defaultdict(list) self.has_path = False - def add_edge(self,u,v): + def add_edge(self, u, v): self.graph[u].append(v) - def dfs(self,x,y): + def dfs(self, x, y): visited = [False] * self.v - self.dfsutil(visited,x,y,) + self.dfsutil(visited, x, y,) - def dfsutil(self,visited,x,y): + def dfsutil(self, visited, x, y): visited[x] = True for i in self.graph[x]: if y in self.graph[x]: self.has_path = True return if(not(visited[i])): - self.dfsutil(visited,x,i) + self.dfsutil(visited, x, i) - def is_reachable(self,x,y): + def is_reachable(self, x, y): self.has_path = False - self.dfs(x,y) + self.dfs(x, y) return self.has_path @@ -36,16 +37,16 @@ def is_reachable(self,x,y): g.add_edge(2, 0) g.add_edge(2, 3) g.add_edge(3, 3) - -u =1; v = 3 - + +u, v = 1, 3 + +if g.is_reachable(u, v): + print("There is a path from %d to %d" % (u, v)) +else: + print("There is no path from %d to %d" % (u, v)) + +u, v = 1, 3 if g.is_reachable(u, v): - print("There is a path from %d to %d" % (u,v)) -else : - print("There is no path from %d to %d" % (u,v)) - -u = 3; v = 1 -if g.is_reachable(u, v) : - print("There is a path from %d to %d" % (u,v)) -else : - print("There is no path from %d to %d" % (u,v)) + print("There is a path from %d to %d" % (u, v)) +else: + print("There is no path from %d to %d" % (u, v)) diff --git a/algorithms/maths/diffie_hellman_key_exchange.py b/algorithms/maths/diffie_hellman_key_exchange.py index 5fed8efa1..91f4e8229 100644 --- a/algorithms/maths/diffie_hellman_key_exchange.py +++ b/algorithms/maths/diffie_hellman_key_exchange.py @@ -1,6 +1,7 @@ import math from random import randint + """ Code from /algorithms/maths/prime_check.py, written by 'goswami-rahul' and 'Hai Honag Dang' @@ -37,7 +38,7 @@ def find_order(a, n): 1 is the order of of 1 """ else: if (math.gcd(a, n) != 1): - print ("a and n should be relative prime!") + print("a and n should be relative prime!") return -1 else: for i in range(1, n): @@ -45,6 +46,7 @@ def find_order(a, n): return i return -1 + """ Euler's totient function, also known as phi-function ϕ(n), counts the number of integers between 1 and n inclusive, @@ -55,15 +57,16 @@ def find_order(a, n): def euler_totient(n): """Euler's totient function or Phi function. Time Complexity: O(sqrt(n)).""" - result = n; + result = n for i in range(2, int(n ** 0.5) + 1): if n % i == 0: while n % i == 0: n //= i result -= result // i if n > 1: - result -= result // n; - return result; + result -= result // n + return result + """ For positive integer n and given integer a that satisfies gcd(a, n) = 1, @@ -81,7 +84,7 @@ def find_primitive_root(n): phi = euler_totient(n) p_root_list = [] """ It will return every primitive roots of n. """ - for i in range (1, n): + for i in range(1, n): if (math.gcd(i, n) != 1): continue """ To have order, a and n must be @@ -103,7 +106,8 @@ def find_primitive_root(n): For example, given a, b and n, it is easy to calculate x that satisfies (a^b) ≡ x (mod n). However, it is very hard to calculate x that satisfies (a^x) ≡ b (mod n). -For using this method, large prime number p and its primitive root a must be given. +For using this method, large prime number p and its primitive root a +must be given. """ def alice_private_key(p): @@ -132,7 +136,7 @@ def bob_public_key(b_pr_k, a, p): with his private key. This is open to public""" return pow(a, b_pr_k) % p - + def alice_shared_key(b_pu_k, a_pr_k, p): """ Alice calculate secret key shared with Bob, @@ -148,12 +152,12 @@ def bob_shared_key(a_pu_k, b_pr_k, p): return pow(a_pu_k, b_pr_k) % p -def diffie_hellman_key_exchange(a, p, option = None): - if (option != None): +def diffie_hellman_key_exchange(a, p, option=None): + if (option is not None): option = 1 """ Print explanation of process when option parameter is given """ - if (prime_check(p) == False): + if (prime_check(p) is False): print("%d is not a prime number" % p) return False """p must be large prime number""" @@ -165,26 +169,25 @@ def diffie_hellman_key_exchange(a, p, option = None): print("%d is not a primitive root of %d" % (a, p)) return False """ a must be primitive root of p """ - + a_pr_k = alice_private_key(p) a_pu_k = alice_public_key(a_pr_k, a, p) - - + b_pr_k = bob_private_key(p) b_pu_k = bob_public_key(b_pr_k, a, p) - + if (option == 1): - print ("Private key of Alice = %d" % a_pr_k) - print ("Public key of Alice = %d" % a_pu_k) - print ("Private key of Bob = %d" % b_pr_k) - print ("Public key of Bob = %d" % b_pu_k) + print("Private key of Alice = %d" % a_pr_k) + print("Public key of Alice = %d" % a_pu_k) + print("Private key of Bob = %d" % b_pr_k) + print("Public key of Bob = %d" % b_pu_k) """ In here, Alice send her public key to Bob, and Bob also send his public key to Alice.""" a_sh_k = alice_shared_key(b_pu_k, a_pr_k, p) b_sh_k = bob_shared_key(a_pu_k, b_pr_k, p) - print ("Shared key calculated by Alice = %d" % a_sh_k) - print ("Shared key calculated by Bob = %d" % b_sh_k) - + print("Shared key calculated by Alice = %d" % a_sh_k) + print("Shared key calculated by Bob = %d" % b_sh_k) + return (a_sh_k == b_sh_k) diff --git a/algorithms/maths/polynomial.py b/algorithms/maths/polynomial.py index 55b59dd91..07a0c3b8a 100644 --- a/algorithms/maths/polynomial.py +++ b/algorithms/maths/polynomial.py @@ -12,7 +12,7 @@ class Monomial: record the details of all variables that a typical monomial is composed of. """ - def __init__(self, variables: Dict[int, int], coeff: Union[int, float, Fraction, None]=None) -> None: + def __init__(self, variables: Dict[int, int], coeff: Union[int, float, Fraction, None]= None) -> None: ''' Create a monomial in the given variables: Examples: @@ -63,7 +63,6 @@ def _rationalize_if_possible(num): else: return num - # def equal_upto_scalar(self, other: Monomial) -> bool: def equal_upto_scalar(self, other) -> bool: """ @@ -353,7 +352,7 @@ def __add__(self, other: Union[int, float, Fraction, Monomial]): return Polynomial([z for z in monos]) elif isinstance(other, Polynomial): temp = list(z for z in {m.clone() for m in self.all_monomials()}) - + p = Polynomial(temp) for o in other.all_monomials(): p = p.__add__(o.clone()) @@ -391,7 +390,7 @@ def __sub__(self, other: Union[int, float, Fraction, Monomial]): for o in other.all_monomials(): p = p.__sub__(o.clone()) return p - + else: raise ValueError('Can only subtract int, float, Fraction, Monomials, or Polynomials from Polynomials.') return @@ -531,4 +530,3 @@ def __str__(self) -> str: the polynomial. """ return ' + '.join(str(m) for m in self.all_monomials() if m.coeff != Fraction(0, 1)) - diff --git a/algorithms/maths/symmetry_group_cycle_index.py b/algorithms/maths/symmetry_group_cycle_index.py index 5f3872ac8..e6d01847e 100644 --- a/algorithms/maths/symmetry_group_cycle_index.py +++ b/algorithms/maths/symmetry_group_cycle_index.py @@ -1,72 +1,72 @@ -from polynomial import ( Monomial, Polynomial ) +from polynomial import (Monomial, Polynomial) from gcd import lcm from fractions import Fraction from typing import Dict, Union """ - The significance of the cycle index (polynomial) of symmetry group - is deeply rooted in counting the number of configurations - of an object excluding those that are symmetric (in terms of permutations). +The significance of the cycle index (polynomial) of symmetry group +is deeply rooted in counting the number of configurations +of an object excluding those that are symmetric (in terms of permutations). - For example, the following problem can be solved as a direct - application of the cycle index polynomial of the symmetry - group. +For example, the following problem can be solved as a direct +application of the cycle index polynomial of the symmetry +group. - Note: I came across this problem as a Google's foo.bar challenge at Level 5 - and solved it using a purely Group Theoretic approach. :) +Note: I came across this problem as a Google's foo.bar challenge at Level 5 +and solved it using a purely Group Theoretic approach. :) +----- - ----- +Problem: - Problem: +Given positive integers +w, h, and s, +compute the number of distinct 2D +grids of dimensions w x h that contain +entries from {0, 1, ..., s-1}. +Note that two grids are defined +to be equivalent if one can be +obtained from the other by +switching rows and columns +some number of times. - Given positive integers - w, h, and s, - compute the number of distinct 2D - grids of dimensions w x h that contain - entries from {0, 1, ..., s-1}. - Note that two grids are defined - to be equivalent if one can be - obtained from the other by - switching rows and columns - some number of times. +----- - ----- +Approach: - Approach: +Compute the cycle index (polynomials) +of S_w, and S_h, i.e. the Symmetry +group on w and h symbols respectively. - Compute the cycle index (polynomials) - of S_w, and S_h, i.e. the Symmetry - group on w and h symbols respectively. +Compute the product of the two +cycle indices while combining two +monomials in such a way that +for any pair of cycles c1, and c2 +in the elements of S_w X S_h, +the resultant monomial contains +terms of the form: +$$ x_{lcm(|c1|, |c2|)}^{gcd(|c1|, |c2|)} $$ - Compute the product of the two - cycle indices while combining two - monomials in such a way that - for any pair of cycles c1, and c2 - in the elements of S_w X S_h, - the resultant monomial contains - terms of the form: - $$ x_{lcm(|c1|, |c2|)}^{gcd(|c1|, |c2|)} $$ +Return the specialization of +the product of cycle indices +at x_i = s (for all the valid i). - Return the specialization of - the product of cycle indices - at x_i = s (for all the valid i). +----- - ----- +Code: - Code: +def solve(w, h, s): - def solve(w, h, s): +s1 = get_cycle_index_sym(w) +s2 = get_cycle_index_sym(h) - s1 = get_cycle_index_sym(w) - s2 = get_cycle_index_sym(h) - - result = cycle_product_for_two_polynomials(s1, s2, s) - - return str(result) +result = cycle_product_for_two_polynomials(s1, s2, s) + +return str(result) """ + def cycle_product(m1: Monomial, m2: Monomial) -> Monomial: """ Given two monomials (from the @@ -132,14 +132,14 @@ def get_cycle_index_sym(n: int) -> Polynomial: """ if n < 0: - raise ValueError('n should be a non-negative integer.') + raise ValueError('n should be a non-negative integer.') memo = { 0: Polynomial([ Monomial({}, Fraction(1, 1)) ]), 1: Polynomial([ - Monomial({1:1}, Fraction(1, 1)) + Monomial({1: 1}, Fraction(1, 1)) ]), 2: Polynomial([ Monomial({1: 2}, Fraction(1, 2)), @@ -148,14 +148,14 @@ def get_cycle_index_sym(n: int) -> Polynomial: 3: Polynomial([ Monomial({1: 3}, Fraction(1, 6)), Monomial({1: 1, 2: 1}, Fraction(1, 2)), - Monomial({3:1}, Fraction(1, 3)) + Monomial({3: 1}, Fraction(1, 3)) ]), 4: Polynomial([ - Monomial({1:4}, Fraction(1, 24)), - Monomial({2:1, 1:2},Fraction(1, 4)), - Monomial({3:1, 1:1}, Fraction(1, 3)), - Monomial({2:2}, Fraction(1, 8)), - Monomial({4:1}, Fraction(1, 4)), + Monomial({1: 4}, Fraction(1, 24)), + Monomial({2: 1, 1: 2}, Fraction(1, 4)), + Monomial({3: 1, 1: 1}, Fraction(1, 3)), + Monomial({2: 2}, Fraction(1, 8)), + Monomial({4: 1}, Fraction(1, 4)), ]) } result = cycle_index_sym_helper(n, memo) diff --git a/algorithms/matrix/bomb_enemy.py b/algorithms/matrix/bomb_enemy.py index debcf5d81..c8412635d 100644 --- a/algorithms/matrix/bomb_enemy.py +++ b/algorithms/matrix/bomb_enemy.py @@ -17,8 +17,10 @@ return 3. (Placing a bomb at (1,1) kills 3 enemies) """ + def max_killed_enemies(grid): - if not grid: return 0 + if not grid: + return 0 m, n = len(grid), len(grid[0]) max_killed = 0 row_e, col_e = 0, [0] * n @@ -38,6 +40,7 @@ def max_killed_enemies(grid): return max_killed + # calculate killed enemies for row i from column j def row_kills(grid, i, j): num = 0 @@ -48,6 +51,7 @@ def row_kills(grid, i, j): j += 1 return num + # calculate killed enemies for column j from row i def col_kills(grid, i, j): num = 0 @@ -57,7 +61,6 @@ def col_kills(grid, i, j): num += 1 i += 1 return num - # ----------------- TESTS ------------------------- @@ -66,14 +69,16 @@ def col_kills(grid, i, j): Testsuite for the project """ -import unittest +import unittest + class TestBombEnemy(unittest.TestCase): def test_3x4(self): - grid1 = [["0","E","0","0"], - ["E","0","W","E"], - ["0","E","0","0"]] - self.assertEqual(3,max_killed_enemies(grid1)) + grid1 = [["0", "E", "0", "0"], + ["E", "0", "W", "E"], + ["0", "E", "0", "0"]] + self.assertEqual(3, max_killed_enemies(grid1)) + def test_4x4(self): grid1 = [ ["0", "E", "0", "E"], @@ -85,9 +90,9 @@ def test_4x4(self): ["E", "0", "0", "0"], ["E", "0", "W", "E"], ["0", "E", "0", "0"]] - self.assertEqual(5,max_killed_enemies(grid1)) - self.assertEqual(3,max_killed_enemies(grid2)) + self.assertEqual(5, max_killed_enemies(grid1)) + self.assertEqual(3, max_killed_enemies(grid2)) + if __name__ == "__main__": unittest.main() - diff --git a/algorithms/matrix/cholesky_matrix_decomposition.py b/algorithms/matrix/cholesky_matrix_decomposition.py index 4b5e24e83..28ef5ea76 100644 --- a/algorithms/matrix/cholesky_matrix_decomposition.py +++ b/algorithms/matrix/cholesky_matrix_decomposition.py @@ -1,6 +1,8 @@ """ -Cholesky matrix decomposition is used to find the decomposition of a Hermitian positive-definite matrix A -into matrix V, so that V * V* = A, where V* denotes the conjugate transpose of L. +Cholesky matrix decomposition is used to find the decomposition of a +Hermitian positive-definite matrix A +into matrix V, so that V * V* = A, where V* denotes the conjugate +transpose of L. The dimensions of the matrix A must match. This method is mainly used for numeric solution of linear equations Ax = b. @@ -25,7 +27,8 @@ def cholesky_decomposition(A): """ :param A: Hermitian positive-definite matrix of type List[List[float]] - :return: matrix of type List[List[float]] if A can be decomposed, otherwise None + :return: matrix of type List[List[float]] if A can be decomposed, + otherwise None """ n = len(A) for ai in A: diff --git a/algorithms/matrix/copy_transform.py b/algorithms/matrix/copy_transform.py index 772a81c9c..99bfa462d 100644 --- a/algorithms/matrix/copy_transform.py +++ b/algorithms/matrix/copy_transform.py @@ -9,6 +9,7 @@ def rotate_clockwise(matrix): new[i].append(elem) return new + def rotate_counterclockwise(matrix): new = [] for row in matrix: @@ -20,6 +21,7 @@ def rotate_counterclockwise(matrix): new[i].append(elem) return new + def top_left_invert(matrix): new = [] for row in matrix: @@ -31,6 +33,7 @@ def top_left_invert(matrix): new[i].append(elem) return new + def bottom_left_invert(matrix): new = [] for row in reversed(matrix): @@ -42,6 +45,7 @@ def bottom_left_invert(matrix): new[i].append(elem) return new + if __name__ == '__main__': def print_matrix(matrix, name): print('{}:\n['.format(name)) diff --git a/algorithms/matrix/crout_matrix_decomposition.py b/algorithms/matrix/crout_matrix_decomposition.py index 46929b517..bfb859bb3 100644 --- a/algorithms/matrix/crout_matrix_decomposition.py +++ b/algorithms/matrix/crout_matrix_decomposition.py @@ -26,6 +26,7 @@ I think the complexity should be O(n^3). """ + def crout_matrix_decomposition(A): n = len(A) L = [[0.0] * n for i in range(n)] @@ -44,4 +45,4 @@ def crout_matrix_decomposition(A): if int(L[j][j]) == 0: L[j][j] = float(0.1**40) U[j][i] = float(tempU/L[j][j]) - return (L,U) + return (L, U) diff --git a/algorithms/matrix/matrix_exponentiation.py b/algorithms/matrix/matrix_exponentiation.py index f9673ce4a..2c836fe07 100644 --- a/algorithms/matrix/matrix_exponentiation.py +++ b/algorithms/matrix/matrix_exponentiation.py @@ -13,18 +13,20 @@ def multiply(matA: list, matB: list) -> list: return matC + def identity(n: int) -> list: """ Returns the Identity matrix of size n x n Time Complexity: O(n^2) """ I = [[0 for i in range(n)] for j in range(n)] - + for i in range(n): I[i][i] = 1 - + return I + def matrix_exponentiation(mat: list, n: int) -> list: """ Calculates mat^n by repeated squaring diff --git a/algorithms/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py index f237fbf44..a8b5e4e77 100644 --- a/algorithms/matrix/rotate_image.py +++ b/algorithms/matrix/rotate_image.py @@ -25,9 +25,9 @@ def rotate(mat): if __name__ == "__main__": - mat = [[1,2,3], - [4,5,6], - [7,8,9]] + mat = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]] print(mat) rotate(mat) print(mat) diff --git a/algorithms/matrix/search_in_sorted_matrix.py b/algorithms/matrix/search_in_sorted_matrix.py index ce3711200..54502c33a 100644 --- a/algorithms/matrix/search_in_sorted_matrix.py +++ b/algorithms/matrix/search_in_sorted_matrix.py @@ -10,13 +10,13 @@ def search_in_a_sorted_matrix(mat, m, n, key): i, j = m-1, 0 while i >= 0 and j < n: if key == mat[i][j]: - print ('Key %s found at row- %s column- %s' % (key, i+1, j+1)) + print('Key %s found at row- %s column- %s' % (key, i+1, j+1)) return if key < mat[i][j]: i -= 1 else: j += 1 - print ('Key %s not found' % (key)) + print('Key %s not found' % (key)) def main(): @@ -27,7 +27,7 @@ def main(): [12, 17, 20] ] key = 13 - print (mat) + print(mat) search_in_a_sorted_matrix(mat, len(mat), len(mat[0]), key) diff --git a/algorithms/matrix/sort_matrix_diagonally.py b/algorithms/matrix/sort_matrix_diagonally.py index 4e9e085d6..b32c71044 100644 --- a/algorithms/matrix/sort_matrix_diagonally.py +++ b/algorithms/matrix/sort_matrix_diagonally.py @@ -32,7 +32,7 @@ def sort_diagonally(mat: List[List[int]]) -> List[List[int]]: for i in range(len(mat)+len(mat[0])-1): # Process the rows if i+1 < len(mat): - # Initialize heap, set row and column + # Initialize heap, set row and column h = [] row = len(mat)-(i+1) col = 0 diff --git a/algorithms/matrix/sparse_dot_vector.py b/algorithms/matrix/sparse_dot_vector.py index 19053ec58..0cba0a575 100644 --- a/algorithms/matrix/sparse_dot_vector.py +++ b/algorithms/matrix/sparse_dot_vector.py @@ -1,7 +1,8 @@ #! /usr/bin/env python3 """ -Suppose we have very large sparse vectors, which contains a lot of zeros and double . +Suppose we have very large sparse vectors, which contains a lot of +zeros and double . find a data structure to store them get the dot product of them diff --git a/algorithms/matrix/sparse_mul.py b/algorithms/matrix/sparse_mul.py index c3b7b61e4..eeaae0eff 100644 --- a/algorithms/matrix/sparse_mul.py +++ b/algorithms/matrix/sparse_mul.py @@ -30,7 +30,8 @@ def multiply(self, a, b): :type B: List[List[int]] :rtype: List[List[int]] """ - if a is None or b is None: return None + if a is None or b is None: + return None m, n, l = len(a), len(b[0]), len(b[0]) if len(b) != n: raise Exception("A's column number must be equal to B's row number.") @@ -39,7 +40,8 @@ def multiply(self, a, b): for k, eleA in enumerate(row): if eleA: for j, eleB in enumerate(b[k]): - if eleB: c[i][j] += eleA * eleB + if eleB: + c[i][j] += eleA * eleB return c @@ -50,7 +52,8 @@ def multiply(self, a, b): :type B: List[List[int]] :rtype: List[List[int]] """ - if a is None or b is None: return None + if a is None or b is None: + return None m, n, l = len(a), len(a[0]), len(b[0]) if len(b) != n: raise Exception("A's column number must be equal to B's row number.") @@ -59,7 +62,8 @@ def multiply(self, a, b): for k, row in enumerate(b): table_b[k] = {} for j, eleB in enumerate(row): - if eleB: table_b[k][j] = eleB + if eleB: + table_b[k][j] = eleB for i, row in enumerate(a): for k, eleA in enumerate(row): if eleA: @@ -67,6 +71,7 @@ def multiply(self, a, b): c[i][j] += eleA * eleB return c + # Python solution with two tables (~196ms): def multiply(self, a, b): """ @@ -74,7 +79,8 @@ def multiply(self, a, b): :type B: List[List[int]] :rtype: List[List[int]] """ - if a is None or b is None: return None + if a is None or b is None: + return None m, n = len(a), len(b[0]) if len(b) != n: raise Exception("A's column number must be equal to B's row number.") @@ -83,17 +89,20 @@ def multiply(self, a, b): for i, row in enumerate(a): for j, ele in enumerate(row): if ele: - if i not in table_a: table_a[i] = {} + if i not in table_a: + table_a[i] = {} table_a[i][j] = ele for i, row in enumerate(b): for j, ele in enumerate(row): if ele: - if i not in table_b: table_b[i] = {} + if i not in table_b: + table_b[i] = {} table_b[i][j] = ele c = [[0 for j in range(l)] for i in range(m)] for i in table_a: for k in table_a[i]: - if k not in table_b: continue + if k not in table_b: + continue for j in table_b[k]: c[i][j] += table_a[i][k] * table_b[k][j] return c diff --git a/algorithms/matrix/sudoku_validator.py b/algorithms/matrix/sudoku_validator.py index 7bda6e424..257fcce8e 100644 --- a/algorithms/matrix/sudoku_validator.py +++ b/algorithms/matrix/sudoku_validator.py @@ -1,12 +1,19 @@ """ -Write a function validSolution/ValidateSolution/valid_solution() that accepts a 2D array representing a Sudoku board, and returns true if it is a valid solution, or false otherwise. The cells of the sudoku board may also contain 0's, which will represent empty cells. Boards containing one or more zeroes are considered to be invalid solutions. -The board is always 9 cells by 9 cells, and every cell only contains integers from 0 to 9. +Write a function validSolution/ValidateSolution/valid_solution() +that accepts a 2D array representing a Sudoku board, and returns true +if it is a valid solution, or false otherwise. The cells of the sudoku +board may also contain 0's, which will represent empty cells. +Boards containing one or more zeroes are considered to be invalid solutions. +The board is always 9 cells by 9 cells, and every cell only contains integers +from 0 to 9. (More info at: http://en.wikipedia.org/wiki/Sudoku) """ # Using dict/hash-table from collections import defaultdict + + def valid_solution_hashtable(board): for i in range(len(board)): dict_row = defaultdict(int) @@ -31,7 +38,7 @@ def valid_solution_hashtable(board): grid_add = 0 for k in range(3): for l in range(3): - grid_add += board[i*3+k][j*3+l] + grid_add += board[i * 3 + k][j * 3 + l] if grid_add != 45: return False return True @@ -65,7 +72,7 @@ def valid_solution(board): # Using set -def valid_solution_set (board): +def valid_solution_set(board): valid = set(range(1, 10)) for row in board: diff --git a/algorithms/matrix/sum_sub_squares.py b/algorithms/matrix/sum_sub_squares.py index 45de7f10c..1231547ef 100644 --- a/algorithms/matrix/sum_sub_squares.py +++ b/algorithms/matrix/sum_sub_squares.py @@ -1,6 +1,6 @@ -# Function to find sum of all -# sub-squares of size k x k in a given -# square matrix of size n x n +# Function to find sum of all +# sub-squares of size k x k in a given +# square matrix of size n x n def sum_sub_squares(matrix, k): n = len(matrix) result = [[0 for i in range(k)] for j in range(k)] @@ -8,17 +8,16 @@ def sum_sub_squares(matrix, k): if k > n: return for i in range(n - k + 1): - l = 0 + l = 0 for j in range(n - k + 1): sum = 0 - - # Calculate and print sum of current sub-square + + # Calculate and print sum of current sub-square for p in range(i, k + i): for q in range(j, k + j): sum += matrix[p][q] - + result[i][l] = sum - l += 1 - - return result + l += 1 + return result diff --git a/algorithms/queues/max_sliding_window.py b/algorithms/queues/max_sliding_window.py index 7d1a45f11..74db65e11 100644 --- a/algorithms/queues/max_sliding_window.py +++ b/algorithms/queues/max_sliding_window.py @@ -18,6 +18,8 @@ """ import collections + + def max_sliding_window(arr, k): qi = collections.deque() # queue storing indexes of elements result = [] diff --git a/algorithms/queues/priority_queue.py b/algorithms/queues/priority_queue.py index 76b08156e..c573ac3cc 100644 --- a/algorithms/queues/priority_queue.py +++ b/algorithms/queues/priority_queue.py @@ -53,4 +53,3 @@ def pop(self): """ # remove and return the first node from the queue return self.priority_queue_list.pop().data - diff --git a/algorithms/queues/queue.py b/algorithms/queues/queue.py index feab56b62..b3ccb4e7f 100644 --- a/algorithms/queues/queue.py +++ b/algorithms/queues/queue.py @@ -13,6 +13,8 @@ * peek() returns the front element of the queue. """ from abc import ABCMeta, abstractmethod + + class AbstractQueue(metaclass=ABCMeta): def __init__(self): @@ -96,6 +98,7 @@ def __init__(self, value): self.value = value self.next = None + class LinkedListQueue(AbstractQueue): def __init__(self): diff --git a/algorithms/queues/zigzagiterator.py b/algorithms/queues/zigzagiterator.py index a8b571f94..5b1e50371 100644 --- a/algorithms/queues/zigzagiterator.py +++ b/algorithms/queues/zigzagiterator.py @@ -5,25 +5,28 @@ def __init__(self, v1, v2): :type v1: List[int] :type v2: List[int] """ - self.queue=[_ for _ in (v1,v2) if _] + self.queue = [_ for _ in (v1, v2) if _] print(self.queue) def next(self): """ :rtype: int """ - v=self.queue.pop(0) - ret=v.pop(0) - if v: self.queue.append(v) + v = self.queue.pop(0) + ret = v.pop(0) + if v: + self.queue.append(v) return ret def has_next(self): """ :rtype: bool """ - if self.queue: return True + if self.queue: + return True return False + l1 = [1, 2] l2 = [3, 4, 5, 6] it = ZigZagIterator(l1, l2) diff --git a/algorithms/set/find_keyboard_row.py b/algorithms/set/find_keyboard_row.py index e00e3683d..c15dcdadf 100644 --- a/algorithms/set/find_keyboard_row.py +++ b/algorithms/set/find_keyboard_row.py @@ -8,6 +8,7 @@ Reference: https://leetcode.com/problems/keyboard-row/description/ """ + def find_keyboard_row(words): """ :type words: List[str] diff --git a/algorithms/stack/is_consecutive.py b/algorithms/stack/is_consecutive.py index f73ddffc7..44e3f90f5 100644 --- a/algorithms/stack/is_consecutive.py +++ b/algorithms/stack/is_consecutive.py @@ -18,14 +18,15 @@ """ import collections + def first_is_consecutive(stack): storage_stack = [] for i in range(len(stack)): first_value = stack.pop() - if len(stack) == 0: # Case odd number of values in stack + if len(stack) == 0: # Case odd number of values in stack return True second_value = stack.pop() - if first_value - second_value != 1: # Not consecutive + if first_value - second_value != 1: # Not consecutive return False stack.append(second_value) # Backup second value storage_stack.append(first_value) @@ -35,14 +36,15 @@ def first_is_consecutive(stack): stack.append(storage_stack.pop()) return True + def second_is_consecutive(stack): q = collections.deque() for i in range(len(stack)): first_value = stack.pop() - if len(stack) == 0: # Case odd number of values in stack + if len(stack) == 0: # Case odd number of values in stack return True second_value = stack.pop() - if first_value - second_value != 1: # Not consecutive + if first_value - second_value != 1: # Not consecutive return False stack.append(second_value) # Backup second value q.append(first_value) diff --git a/algorithms/stack/is_sorted.py b/algorithms/stack/is_sorted.py index 0a69d83f9..b3c3337e5 100644 --- a/algorithms/stack/is_sorted.py +++ b/algorithms/stack/is_sorted.py @@ -9,6 +9,8 @@ bottom [1, 2, 3, 4, 5, 6] top The function should return true """ + + def is_sorted(stack): storage_stack = [] for i in range(len(stack)): diff --git a/algorithms/stack/longest_abs_path.py b/algorithms/stack/longest_abs_path.py index 67aad5a6a..edc4ee8b0 100644 --- a/algorithms/stack/longest_abs_path.py +++ b/algorithms/stack/longest_abs_path.py @@ -1,37 +1,37 @@ # def lengthLongestPath(input): - # maxlen = 0 - # pathlen = {0: 0} - # for line in input.splitlines(): - # print("---------------") - # print("line:", line) - # name = line.strip('\t') - # print("name:", name) - # depth = len(line) - len(name) - # print("depth:", depth) - # if '.' in name: - # maxlen = max(maxlen, pathlen[depth] + len(name)) - # else: - # pathlen[depth + 1] = pathlen[depth] + len(name) + 1 - # print("maxlen:", maxlen) - # return maxlen +# maxlen = 0 +# pathlen = {0: 0} +# for line in input.splitlines(): +# print("---------------") +# print("line:", line) +# name = line.strip('\t') +# print("name:", name) +# depth = len(line) - len(name) +# print("depth:", depth) +# if '.' in name: +# maxlen = max(maxlen, pathlen[depth] + len(name)) +# else: +# pathlen[depth + 1] = pathlen[depth] + len(name) + 1 +# print("maxlen:", maxlen) +# return maxlen # def lengthLongestPath(input): - # paths = input.split("\n") - # level = [0] * 10 - # maxLength = 0 - # for path in paths: - # print("-------------") - # levelIdx = path.rfind("\t") - # print("Path: ", path) - # print("path.rfind(\\t)", path.rfind("\t")) - # print("levelIdx: ", levelIdx) - # print("level: ", level) - # level[levelIdx + 1] = level[levelIdx] + len(path) - levelIdx + 1 - # print("level: ", level) - # if "." in path: - # maxLength = max(maxLength, level[levelIdx+1] - 1) - # print("maxlen: ", maxLength) - # return maxLength +# paths = input.split("\n") +# level = [0] * 10 +# maxLength = 0 +# for path in paths: +# print("-------------") +# levelIdx = path.rfind("\t") +# print("Path: ", path) +# print("path.rfind(\\t)", path.rfind("\t")) +# print("levelIdx: ", levelIdx) +# print("level: ", level) +# level[levelIdx + 1] = level[levelIdx] + len(path) - levelIdx + 1 +# print("level: ", level) +# if "." in path: +# maxLength = max(maxLength, level[levelIdx+1] - 1) +# print("maxlen: ", maxLength) +# return maxLength def length_longest_path(input): """ @@ -57,9 +57,9 @@ def length_longest_path(input): max_len = max(max_len, curr_len-1) # -1 is to minus one '/' return max_len -st= "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdirectory1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" + +st = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdirectory1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" st2 = "a\n\tb1\n\t\tf1.txt\n\taaaaa\n\t\tf2.txt" print("path:", st2) print("answer:", length_longest_path(st2)) - diff --git a/algorithms/stack/ordered_stack.py b/algorithms/stack/ordered_stack.py index 7a30d143e..94191d6cf 100644 --- a/algorithms/stack/ordered_stack.py +++ b/algorithms/stack/ordered_stack.py @@ -1,33 +1,36 @@ -#The stack remains always ordered such that the highest value is at the top and the lowest at the bottom +# The stack remains always ordered such that the highest value +# is at the top and the lowest at the bottom + class OrderedStack: - def __init__(self): - self.items = [] - - def is_empty(self): - return self.items == [] - - def push_t(self, item): - self.items.append(item) - - def push(self, item): #push method to maintain order when pushing new elements - temp_stack = OrderedStack() - if self.is_empty() or item > self.peek(): - self.push_t(item) - else: - while item < self.peek() and not self.is_empty(): - temp_stack.push_t(self.pop()) - self.push_t(item) - while not temp_stack.is_empty(): - self.push_t(temp_stack.pop()) - - def pop(self): - if self.is_empty(): - raise IndexError("Stack is empty") - return self.items.pop() - - def peek(self): - return self.items[len(self.items) - 1] - - def size(self): - return len(self.items) + def __init__(self): + self.items = [] + + def is_empty(self): + return self.items == [] + + def push_t(self, item): + self.items.append(item) + + # push method to maintain order when pushing new elements + def push(self, item): + temp_stack = OrderedStack() + if self.is_empty() or item > self.peek(): + self.push_t(item) + else: + while item < self.peek() and not self.is_empty(): + temp_stack.push_t(self.pop()) + self.push_t(item) + while not temp_stack.is_empty(): + self.push_t(temp_stack.pop()) + + def pop(self): + if self.is_empty(): + raise IndexError("Stack is empty") + return self.items.pop() + + def peek(self): + return self.items[len(self.items) - 1] + + def size(self): + return len(self.items) diff --git a/algorithms/stack/remove_min.py b/algorithms/stack/remove_min.py index 1cd8fc6ae..ce635a4ab 100644 --- a/algorithms/stack/remove_min.py +++ b/algorithms/stack/remove_min.py @@ -8,6 +8,8 @@ bottom [2, 8, 3, 7, 3] top """ + + def remove_min(stack): storage_stack = [] if len(stack) == 0: # Stack is empty diff --git a/algorithms/stack/simplify_path.py b/algorithms/stack/simplify_path.py index fed4385a6..09f9de826 100644 --- a/algorithms/stack/simplify_path.py +++ b/algorithms/stack/simplify_path.py @@ -7,8 +7,9 @@ * Did you consider the case where path = "/../"? In this case, you should return "/". -* Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". - In this case, you should ignore redundant slashes and return "/home/foo". +* Another corner case is the path might contain multiple slashes '/' together, + such as "/home//foo/". In this case, you should ignore redundant + slashes and return "/home/foo". """ def simplify_path(path): """ diff --git a/algorithms/stack/stack.py b/algorithms/stack/stack.py index d1a148e36..a79aec490 100644 --- a/algorithms/stack/stack.py +++ b/algorithms/stack/stack.py @@ -12,6 +12,8 @@ It needs no parameters and returns a boolean value. """ from abc import ABCMeta, abstractmethod + + class AbstractStack(metaclass=ABCMeta): """Abstract Class for Stacks.""" def __init__(self): diff --git a/algorithms/stack/stutter.py b/algorithms/stack/stutter.py index 30314992c..ceb6451d4 100644 --- a/algorithms/stack/stutter.py +++ b/algorithms/stack/stutter.py @@ -13,6 +13,7 @@ """ import collections + def first_stutter(stack): storage_stack = [] for i in range(len(stack)): @@ -24,6 +25,7 @@ def first_stutter(stack): return stack + def second_stutter(stack): q = collections.deque() # Put all values into queue from stack diff --git a/algorithms/stack/switch_pairs.py b/algorithms/stack/switch_pairs.py index f5db2280d..d8b22dc08 100644 --- a/algorithms/stack/switch_pairs.py +++ b/algorithms/stack/switch_pairs.py @@ -4,13 +4,15 @@ For example, if the stack initially stores these values: bottom [3, 8, 17, 9, 1, 10] top -Your function should switch the first pair (3, 8), the second pair (17, 9), ...: +Your function should switch the first pair (3, 8), +the second pair (17, 9), ...: bottom [8, 3, 9, 17, 10, 1] top if there are an odd number of values in the stack, the value at the top of the stack is not moved: For example: bottom [3, 8, 17, 9, 1] top -It would again switch pairs of values, but the value at the top of the stack (1) +It would again switch pairs of values, but the value at the +top of the stack (1) would not be moved bottom [8, 3, 9, 17, 1] top @@ -20,6 +22,7 @@ """ import collections + def first_switch_pairs(stack): storage_stack = [] for i in range(len(stack)): @@ -36,6 +39,7 @@ def first_switch_pairs(stack): stack.append(first) return stack + def second_switch_pairs(stack): q = collections.deque() # Put all values into queue from stack diff --git a/algorithms/stack/valid_parenthesis.py b/algorithms/stack/valid_parenthesis.py index b62ac02c4..8fdb861b5 100644 --- a/algorithms/stack/valid_parenthesis.py +++ b/algorithms/stack/valid_parenthesis.py @@ -6,6 +6,8 @@ The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not. """ + + def is_valid(s: str) -> bool: stack = [] dic = {")": "(", diff --git a/tests/test_iterative_segment_tree.py b/tests/test_iterative_segment_tree.py index 77c0283ba..66d222267 100644 --- a/tests/test_iterative_segment_tree.py +++ b/tests/test_iterative_segment_tree.py @@ -74,7 +74,7 @@ def __test_all_segments(self, arr, fnc): """ Test all possible segments in the tree :param arr: array to test - :param fnc: function of the segment tree + :param fnc: function of the segment tpree """ segment_tree = SegmentTree(arr, fnc) self.__test_segments_helper(segment_tree, fnc, arr) From 3259a07a955661b51082f2f933888eb62c277c22 Mon Sep 17 00:00:00 2001 From: Christofer Nolander Date: Mon, 7 Mar 2022 12:17:05 +0100 Subject: [PATCH 280/302] Pylint refactor (#851) * refactor(pylint): unionfind/count_islands.py improves pylint score from 3.71 to 10.00 fixes https://github.com/KTH-Software-Engineering-DD2480/algorithms/issues/2 * refactor(pylint): algorithms/search/*.py improves pylint score from 5.83 to 10.00. fixes https://github.com/KTH-Software-Engineering-DD2480/algorithms/issues/7 * feat: improving pylint score * refactor dp.combination_sum: lint score from 5.42 to 9.13 * refactor(pylint): algorithms/graph/*.py Improves pylint score from 5.51 to 9.96. Score is lower than 10 due to duplication between maximum_flow_bfs.py and maximum_flow_dfs.py. However, due to the educational nature of this repo, keeping it as is will probably be benefitial as it reduces complexity while reading (having to jump between files). fixes https://github.com/KTH-Software-Engineering-DD2480/algorithms/issues/9 * refactor egg_drop, hosoya_triangle, min_cost_path and planting_trees * feat: improving pylint score of one_sparse_recovery * refactor: move tests from regex_matching to tests folder * refactor: lint score from 4.27 to 9.46 a reason that lint score isn't 10.00 is that the module is called dp, which in turn makes pylint raise invalid name for all files in dp. I leave that as it is, since I don't want to mess with the current folder structure. fixes #3 * Fix: Fixed lint error, lint value now aboe 8 * refactor: add docstring to misra, score 10 * fix (misra): add a newline * refactor: add docstring for one_sparse, score 9.33 * wip: refactor (pylint): algorithms/maths/ wip: #4 * Fix: pylint is above 8 for tree * refactor (pylint): algorithms/maths/ Finished improving pylint score for maths folder. fixes: #4 * Fixed: comments * fix: small intendation fix Co-authored-by: ekorre1001 Co-authored-by: Philip Salqvist Co-authored-by: psalqvist <63300368+psalqvist@users.noreply.github.com> Co-authored-by: Kubha99 <1kunalbhatnagar@gmail.com> Co-authored-by: mantaur --- algorithms/dp/__init__.py | 2 +- algorithms/dp/climbing_stairs.py | 24 +- algorithms/dp/coin_change.py | 31 +-- algorithms/dp/combination_sum.py | 56 +++-- algorithms/dp/edit_distance.py | 32 +-- algorithms/dp/egg_drop.py | 7 +- algorithms/dp/fib.py | 11 +- algorithms/dp/hosoya_triangle.py | 49 ++-- algorithms/dp/int_divide.py | 17 +- algorithms/dp/job_scheduling.py | 67 +++--- algorithms/dp/k_factor.py | 133 +++++------ algorithms/dp/longest_common_subsequence.py | 22 +- algorithms/dp/longest_increasing.py | 87 ++++---- algorithms/dp/matrix_chain_order.py | 29 ++- algorithms/dp/max_product_subarray.py | 25 +-- algorithms/dp/min_cost_path.py | 29 +-- algorithms/dp/num_decodings.py | 34 +-- algorithms/dp/planting_trees.py | 46 ++-- algorithms/dp/regex_matching.py | 127 ++++------- algorithms/dp/rod_cut.py | 22 +- algorithms/dp/word_break.py | 29 ++- algorithms/graph/__init__.py | 4 + algorithms/graph/all_pairs_shortest_path.py | 32 ++- algorithms/graph/bellman_ford.py | 40 ++-- algorithms/graph/check_bipartite.py | 39 ++-- .../graph/check_digraph_strongly_connected.py | 116 +++++----- algorithms/graph/clone_graph.py | 70 ++++-- .../count_connected_number_of_component.py | 43 ++-- algorithms/graph/cycle_detection.py | 41 ++-- algorithms/graph/dijkstra.py | 49 ++-- algorithms/graph/find_all_cliques.py | 21 +- algorithms/graph/find_path.py | 31 +-- algorithms/graph/graph.py | 92 ++++---- algorithms/graph/markov_chain.py | 31 ++- algorithms/graph/maximum_flow.py | 89 ++++---- algorithms/graph/maximum_flow_bfs.py | 45 ++-- algorithms/graph/maximum_flow_dfs.py | 42 ++-- algorithms/graph/minimum_spanning_tree.py | 209 ++++++++++-------- .../path_between_two_vertices_in_digraph.py | 95 ++++---- algorithms/graph/prims_minimum_spanning.py | 48 ++-- algorithms/graph/satisfiability.py | 91 +++++--- algorithms/graph/tarjan.py | 54 +++-- algorithms/graph/transitive_closure_dfs.py | 69 +++--- algorithms/graph/traversal.py | 60 ++--- algorithms/heap/binary_heap.py | 65 +++--- algorithms/heap/k_closest_points.py | 18 +- algorithms/heap/merge_sorted_k_lists.py | 24 +- algorithms/maths/__init__.py | 4 +- algorithms/maths/base_conversion.py | 37 ++-- algorithms/maths/chinese_remainder_theorem.py | 52 ++--- algorithms/maths/combination.py | 6 +- algorithms/maths/cosine_similarity.py | 23 +- algorithms/maths/decimal_to_binary_ip.py | 8 + .../maths/diffie_hellman_key_exchange.py | 133 ++++++----- algorithms/maths/euler_totient.py | 6 +- algorithms/maths/extended_gcd.py | 17 +- algorithms/maths/factorial.py | 3 + algorithms/maths/find_order_simple.py | 40 ++-- .../maths/find_primitive_root_simple.py | 68 +++--- algorithms/maths/gcd.py | 18 +- algorithms/maths/generate_strobogrammtic.py | 10 +- algorithms/maths/hailstone.py | 30 ++- algorithms/maths/is_strobogrammatic.py | 3 +- algorithms/maths/krishnamurthy_number.py | 11 +- algorithms/maths/magic_number.py | 13 +- algorithms/maths/modular_inverse.py | 14 +- algorithms/maths/next_bigger.py | 8 +- algorithms/maths/next_perfect_square.py | 12 +- algorithms/maths/nth_digit.py | 2 +- algorithms/maths/num_digits.py | 11 +- algorithms/maths/power.py | 33 +-- .../maths/primes_sieve_of_eratosthenes.py | 1 - algorithms/maths/pythagoras.py | 18 +- algorithms/maths/rabin_miller.py | 2 +- .../maths/recursive_binomial_coefficient.py | 6 +- algorithms/maths/rsa.py | 27 +-- algorithms/maths/summing_digits.py | 13 +- .../maths/symmetry_group_cycle_index.py | 21 +- algorithms/search/__init__.py | 4 + algorithms/search/binary_search.py | 52 +++-- algorithms/search/find_min_rotate.py | 11 +- algorithms/search/first_occurrence.py | 31 +-- algorithms/search/interpolation_search.py | 6 +- algorithms/search/jump_search.py | 41 ++-- algorithms/search/last_occurrence.py | 26 ++- algorithms/search/linear_search.py | 19 +- algorithms/search/next_greatest_letter.py | 20 +- algorithms/search/search_insert.py | 20 +- algorithms/search/search_rotate.py | 19 +- algorithms/search/ternary_search.py | 51 +++-- algorithms/search/two_sum.py | 50 +++-- algorithms/streaming/misra_gries.py | 75 ++++--- algorithms/streaming/one_sparse_recovery.py | 91 ++++---- algorithms/tree/avl/avl.py | 8 +- algorithms/tree/b_tree.py | 66 +++--- algorithms/tree/same_tree.py | 8 +- algorithms/tree/traversal/inorder.py | 11 +- algorithms/tree/traversal/preorder.py | 6 +- algorithms/unionfind/count_islands.py | 180 +++++++++------ tests/test_dp.py | 53 ++++- tests/test_graph.py | 71 ++++++ tests/test_heap.py | 4 +- 102 files changed, 2235 insertions(+), 1735 deletions(-) diff --git a/algorithms/dp/__init__.py b/algorithms/dp/__init__.py index ac56eda74..442120282 100644 --- a/algorithms/dp/__init__.py +++ b/algorithms/dp/__init__.py @@ -20,4 +20,4 @@ from .word_break import * from .int_divide import * from .k_factor import * -from .planting_trees import * \ No newline at end of file +from .planting_trees import * diff --git a/algorithms/dp/climbing_stairs.py b/algorithms/dp/climbing_stairs.py index 0c02efe51..9b90ae15c 100644 --- a/algorithms/dp/climbing_stairs.py +++ b/algorithms/dp/climbing_stairs.py @@ -1,23 +1,23 @@ """ You are climbing a stair case. -It takes n steps to reach to the top. +It takes `steps` number of steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? -Note: Given n will be a positive integer. +Note: Given argument `steps` will be a positive integer. """ # O(n) space -def climb_stairs(n): +def climb_stairs(steps): """ - :type n: int + :type steps: int :rtype: int """ arr = [1, 1] - for _ in range(1, n): + for _ in range(1, steps): arr.append(arr[-1] + arr[-2]) return arr[-1] @@ -25,8 +25,12 @@ def climb_stairs(n): # the above function can be optimized as: # O(1) space -def climb_stairs_optimized(n): - a = b = 1 - for _ in range(n): - a, b = b, a + b - return a +def climb_stairs_optimized(steps): + """ + :type steps: int + :rtype: int + """ + a_steps = b_steps = 1 + for _ in range(steps): + a_steps, b_steps = b_steps, a_steps + b_steps + return a_steps diff --git a/algorithms/dp/coin_change.py b/algorithms/dp/coin_change.py index a1d739d9b..379753b06 100644 --- a/algorithms/dp/coin_change.py +++ b/algorithms/dp/coin_change.py @@ -1,31 +1,34 @@ """ Problem -Given a value n, if we want to make change for N cents, -and we have infinite supply of each of -coins = {S1, S2, .. , Sm} valued coins, how many ways -can we make the change? -The order of coins doesn't matter. -For example, for n = 4 and coins = [1, 2, 3], there are -four solutions: +Given a value `value`, if we want to make change for `value` cents, and we have infinite +supply of each of coins = {S1, S2, .. , Sm} valued `coins`, how many ways can we make the change? +The order of `coins` doesn't matter. +For example, for `value` = 4 and `coins` = [1, 2, 3], there are four solutions: [1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3]. So output should be 4. -For n = 10 and coins = [2, 5, 3, 6], there are five solutions: +For `value` = 10 and `coins` = [2, 5, 3, 6], there are five solutions: + [2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]. So the output should be 5. -Time complexity: O(n * m) where n is the value and m is the number of coins +Time complexity: O(n * m) where n is the `value` and m is the number of `coins` Space complexity: O(n) """ +def count(coins, value): + """ Find number of combination of `coins` that adds upp to `value` -def count(coins, n): + Keyword arguments: + coins -- int[] + value -- int + """ # initialize dp array and set base case as 1 - dp = [1] + [0] * n + dp_array = [1] + [0] * value # fill dp in a bottom up manner for coin in coins: - for i in range(coin, n+1): - dp[i] += dp[i-coin] + for i in range(coin, value+1): + dp_array[i] += dp_array[i-coin] - return dp[n] + return dp_array[value] diff --git a/algorithms/dp/combination_sum.py b/algorithms/dp/combination_sum.py index 57587ff91..aaf0749e8 100644 --- a/algorithms/dp/combination_sum.py +++ b/algorithms/dp/combination_sum.py @@ -27,34 +27,48 @@ """ -dp = None - +DP = None def helper_topdown(nums, target): - global dp - if dp[target] != -1: - return dp[target] + """Generates DP and finds result. + + Keyword arguments: + nums -- positive integer array without duplicates + target -- integer describing what a valid combination should add to + """ + if DP[target] != -1: + return DP[target] res = 0 - for i in range(0, len(nums)): - if target >= nums[i]: - res += helper_topdown(nums, target - nums[i]) - dp[target] = res + for num in nums: + if target >= num: + res += helper_topdown(nums, target - num) + DP[target] = res return res def combination_sum_topdown(nums, target): - global dp - dp = [-1] * (target + 1) - dp[0] = 1 - return helper_topdown(nums, target) + """Find number of possible combinations in nums that add up to target, in top-down manner. + Keyword arguments: + nums -- positive integer array without duplicates + target -- integer describing what a valid combination should add to + """ + global DP + DP = [-1] * (target + 1) + DP[0] = 1 + return helper_topdown(nums, target) -# EDIT: The above solution is top-down. How about a bottom-up one? def combination_sum_bottom_up(nums, target): - comb = [0] * (target + 1) - comb[0] = 1 - for i in range(0, len(comb)): - for j in range(len(nums)): - if i - nums[j] >= 0: - comb[i] += comb[i - nums[j]] - return comb[target] + """Find number of possible combinations in nums that add up to target, in bottom-up manner. + + Keyword arguments: + nums -- positive integer array without duplicates + target -- integer describing what a valid combination should add to + """ + combs = [0] * (target + 1) + combs[0] = 1 + for i in range(0, len(combs)): + for num in nums: + if i - num >= 0: + combs[i] += combs[i - num] + return combs[target] diff --git a/algorithms/dp/edit_distance.py b/algorithms/dp/edit_distance.py index c21c766b7..caf56eedc 100644 --- a/algorithms/dp/edit_distance.py +++ b/algorithms/dp/edit_distance.py @@ -36,28 +36,34 @@ indexes i and j, respectively. To find the edit distance between two words A and B, -we need to find edit(m, n), where m is the length of A and n -is the length of B. +we need to find edit(length_a, length_b). + +Time: O(length_a*length_b) +Space: O(length_a*length_b) """ -def edit_distance(A, B): - # Time: O(m*n) - # Space: O(m*n) +def edit_distance(word_a, word_b): + """Finds edit distance between word_a and word_b + + Kwyword arguments: + word_a -- string + word_b -- string + """ - m, n = len(A) + 1, len(B) + 1 + length_a, length_b = len(word_a) + 1, len(word_b) + 1 - edit = [[0 for _ in range(n)] for _ in range(m)] + edit = [[0 for _ in range(length_b)] for _ in range(length_a)] - for i in range(1, m): + for i in range(1, length_a): edit[i][0] = i - for j in range(1, n): + for j in range(1, length_b): edit[0][j] = j - for i in range(1, m): - for j in range(1, n): - cost = 0 if A[i - 1] == B[j - 1] else 1 + for i in range(1, length_a): + for j in range(1, length_b): + cost = 0 if word_a[i - 1] == word_b[j - 1] else 1 edit[i][j] = min(edit[i - 1][j] + 1, edit[i][j - 1] + 1, edit[i - 1][j - 1] + cost) - return edit[-1][-1] # this is the same as edit[m][n] + return edit[-1][-1] # this is the same as edit[length_a][length_b] diff --git a/algorithms/dp/egg_drop.py b/algorithms/dp/egg_drop.py index b9d38508a..dfa232019 100644 --- a/algorithms/dp/egg_drop.py +++ b/algorithms/dp/egg_drop.py @@ -26,9 +26,14 @@ def egg_drop(n, k): + """ + Keyword arguments: + n -- number of floors + k -- number of eggs + """ # A 2D table where entery eggFloor[i][j] will represent minimum # number of trials needed for i eggs and j floors. - egg_floor = [[0 for x in range(k+1)] for x in range(n + 1)] + egg_floor = [[0 for _ in range(k + 1)] for _ in range(n + 1)] # We need one trial for one floor and 0 trials for 0 floors for i in range(1, n+1): diff --git a/algorithms/dp/fib.py b/algorithms/dp/fib.py index f51020b74..08fa8ea02 100644 --- a/algorithms/dp/fib.py +++ b/algorithms/dp/fib.py @@ -35,8 +35,7 @@ def fib_recursive(n): if n <= 1: return n - else: - return fib_recursive(n-1) + fib_recursive(n-2) + return fib_recursive(n-1) + fib_recursive(n-2) # print(fib_recursive(35)) # => 9227465 (slow) @@ -81,13 +80,13 @@ def fib_iter(n): fib_1 = 0 fib_2 = 1 - sum = 0 + res = 0 if n <= 1: return n for _ in range(n-1): - sum = fib_1 + fib_2 + res = fib_1 + fib_2 fib_1 = fib_2 - fib_2 = sum - return sum + fib_2 = res + return res # print(fib_iter(100)) # => 354224848179261915075 diff --git a/algorithms/dp/hosoya_triangle.py b/algorithms/dp/hosoya_triangle.py index d2e1a8587..a63deaf48 100644 --- a/algorithms/dp/hosoya_triangle.py +++ b/algorithms/dp/hosoya_triangle.py @@ -19,29 +19,38 @@ """ +def hosoya(height, width): + """ Calculates the hosoya triangle -def hosoya(n, m): - if ((n == 0 and m == 0) or (n == 1 and m == 0) or - (n == 1 and m == 1) or (n == 2 and m == 1)): + height -- height of the triangle + """ + if (width == 0) and (height in (0,1)): return 1 - if n > m: - return hosoya(n - 1, m) + hosoya(n - 2, m) - elif m == n: - return hosoya(n - 1, m - 1) + hosoya(n - 2, m - 2) - else: - return 0 - - -def print_hosoya(n): - for i in range(n): + if (width == 1) and (height in (1,2)): + return 1 + if height > width: + return hosoya(height - 1, width) + hosoya(height - 2, width) + if width == height: + return hosoya(height - 1, width - 1) + hosoya(height - 2, width - 2) + return 0 + +def print_hosoya(height): + """Prints the hosoya triangle + + height -- height of the triangle + """ + for i in range(height): for j in range(i + 1): - print(hosoya(i, j), end=" ") - print("\n", end="") + print(hosoya(i, j) , end = " ") + print ("\n", end = "") +def hosoya_testing(height): + """Test hosoya function -def hosoya_testing(n): - x = [] - for i in range(n): + height -- height of the triangle + """ + res = [] + for i in range(height): for j in range(i + 1): - x.append(hosoya(i, j)) - return x + res.append(hosoya(i, j)) + return res diff --git a/algorithms/dp/int_divide.py b/algorithms/dp/int_divide.py index 86ba8cbb6..37c9a44e1 100644 --- a/algorithms/dp/int_divide.py +++ b/algorithms/dp/int_divide.py @@ -1,5 +1,6 @@ """ -Given positive integer n, find an algorithm to find the number of non-negative number division, or descomposition. +Given positive integer decompose, find an algorithm to find the number of +non-negative number division, or decomposition. The complexity is O(n^2). @@ -36,15 +37,19 @@ """ -def int_divide(n): - arr = [[0 for i in range(n + 1)] for j in range(n + 1)] +def int_divide(decompose): + """Find number of decompositions from `decompose` + + decompose -- integer + """ + arr = [[0 for i in range(decompose + 1)] for j in range(decompose + 1)] arr[1][1] = 1 - for i in range(1, n + 1): - for j in range(1, n + 1): + for i in range(1, decompose + 1): + for j in range(1, decompose + 1): if i < j: arr[i][j] = arr[i][i] elif i == j: arr[i][j] = 1 + arr[i][j - 1] else: arr[i][j] = arr[i][j - 1] + arr[i - j][j] - return arr[n][n] + return arr[decompose][decompose] diff --git a/algorithms/dp/job_scheduling.py b/algorithms/dp/job_scheduling.py index f1a92f584..b822c032c 100644 --- a/algorithms/dp/job_scheduling.py +++ b/algorithms/dp/job_scheduling.py @@ -1,65 +1,68 @@ -# Python program for weighted job scheduling using Dynamic -# Programming and Binary Search - -# Class to represent a job - +""" +Python program for weighted job scheduling using Dynamic +Programming and Binary Search +""" class Job: + """ + Class to represent a job + """ def __init__(self, start, finish, profit): self.start = start self.finish = finish - self.profit = profit - + self.profit = profit -# A Binary Search based function to find the latest job -# (before current job) that doesn't conflict with current -# job. "index" is index of the current job. This function -# returns -1 if all jobs before index conflict with it. -# The array jobs[] is sorted in increasing order of finish -# time. def binary_search(job, start_index): - - # Initialize 'lo' and 'hi' for Binary Search - lo = 0 - hi = start_index - 1 + """ + A Binary Search based function to find the latest job + (before current job) that doesn't conflict with current + job. "index" is index of the current job. This function + returns -1 if all jobs before index conflict with it. + The array jobs[] is sorted in increasing order of finish + time. + """ + + left = 0 + right = start_index - 1 # Perform binary Search iteratively - while lo <= hi: - mid = (lo + hi) // 2 + while left <= right: + mid = (left + right) // 2 if job[mid].finish <= job[start_index].start: if job[mid + 1].finish <= job[start_index].start: - lo = mid + 1 + left = mid + 1 else: return mid else: - hi = mid - 1 + right = mid - 1 return -1 - -# The main function that returns the maximum possible -# profit from given array of jobs def schedule(job): + """ + The main function that returns the maximum possible + profit from given array of jobs + """ # Sort jobs according to finish time - job = sorted(job, key=lambda j: j.finish) + job = sorted(job, key = lambda j: j.finish) # Create an array to store solutions of subproblems. table[i] # stores the profit for jobs till arr[i] (including arr[i]) - n = len(job) - table = [0 for _ in range(n)] + length = len(job) + table = [0 for _ in range(length)] table[0] = job[0].profit # Fill entries in table[] using recursive property - for i in range(1, n): + for i in range(1, length): # Find profit including the current job incl_prof = job[i].profit - l = binary_search(job, i) - if (l != -1): - incl_prof += table[l] + pos = binary_search(job, i) + if pos != -1: + incl_prof += table[pos] # Store maximum of including and excluding table[i] = max(incl_prof, table[i - 1]) - return table[n-1] + return table[length-1] diff --git a/algorithms/dp/k_factor.py b/algorithms/dp/k_factor.py index 998d825ee..c072f7541 100644 --- a/algorithms/dp/k_factor.py +++ b/algorithms/dp/k_factor.py @@ -1,78 +1,85 @@ -'''The K factor of a string is defined as the number of -times 'abba' appears as a substring. - -Given two numbers N and k, find the number of strings of -length N with 'K factor' = k. +''' +The K factor of a string is defined as the number of times 'abba' appears as a +substring. Given two numbers `length` and `k_factor`, find the number of +strings of length `length` with 'K factor' = `k_factor`. The algorithms is as follows: -dp[n][k] will be a 4 element array, wherein each element can be -the number of strings of length n and 'K factor' = k which -belong to the criteria represented by that index: +dp[length][k_factor] will be a 4 element array, wherein each element can be the +number of strings of length `length` and 'K factor' = `k_factor` which belong +to the criteria represented by that index: + + - dp[length][k_factor][0] can be the number of strings of length `length` + and K-factor = `k_factor` which end with substring 'a' + + - dp[length][k_factor][1] can be the number of strings of length `length` + and K-factor = `k_factor` which end with substring 'ab' + + - dp[length][k_factor][2] can be the number of strings of length `length` + and K-factor = `k_factor` which end with substring 'abb' - dp[n][k][0] can be the number of strings of length n and K-factor = k - which end with substring 'a' - dp[n][k][1] can be the number of strings of length n and K-factor = k - which end with substring 'ab' - dp[n][k][2] can be the number of strings of length n and K-factor = k - which end with substring 'abb' - dp[n][k][3] can be the number of strings of length n and K-factor = k - which end with anything other than the above substrings (anything other - than 'a' 'ab' 'abb') + - dp[length][k_factor][3] can be the number of strings of `length` and + K-factor = `k_factor` which end with anything other than the above + substrings (anything other than 'a' 'ab' 'abb') Example inputs -n=4 k=1 no of strings = 1 -n=7 k=1 no of strings = 70302 -n=10 k=2 no of strings = 74357 +length=4 k_factor=1 no of strings = 1 +length=7 k_factor=1 no of strings = 70302 +length=10 k_factor=2 no of strings = 74357 ''' +def find_k_factor(length, k_factor): + """Find the number of strings of length `length` with K factor = `k_factor`. -def find_k_factor(n, k): - dp = [[[0 for i in range(4)]for j in range((n-1)//3+2)]for k in range(n+1)] - if(3*k+1 > n): + Keyword arguments: + length -- integer + k_factor -- integer + """ + mat=[[[0 for i in range(4)]for j in range((length-1)//3+2)]for k in range(length+1)] + if 3*k_factor+1>length: return 0 - # base cases - dp[1][0][0] = 1 - dp[1][0][1] = 0 - dp[1][0][2] = 0 - dp[1][0][3] = 25 - - for i in range(2, n+1): - for j in range((n-1)//3+2): - if(j == 0): - # adding a at the end - dp[i][j][0] = dp[i-1][j][0] + dp[i-1][j][1] + dp[i-1][j][3] - - # adding b at the end - dp[i][j][1] = dp[i-1][j][0] - dp[i][j][2] = dp[i-1][j][1] - - # adding any other lowercase character - dp[i][j][3] = dp[i-1][j][0]*24+dp[i-1][j][1]*24+dp[i-1][j][2]*25+dp[i-1][j][3]*25 - - elif(3*j+1 < i): - # adding a at the end - dp[i][j][0] = dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][j][3]+dp[i-1][j-1][2] - - # adding b at the end - dp[i][j][1] = dp[i-1][j][0] - dp[i][j][2] = dp[i-1][j][1] - - # adding any other lowercase character - dp[i][j][3] = dp[i-1][j][0]*24+dp[i-1][j][1]*24+dp[i-1][j][2]*25+dp[i-1][j][3]*25 - - elif(3*j+1 == i): - dp[i][j][0] = 1 - dp[i][j][1] = 0 - dp[i][j][2] = 0 - dp[i][j][3] = 0 + #base cases + mat[1][0][0]=1 + mat[1][0][1]=0 + mat[1][0][2]=0 + mat[1][0][3]=25 + + for i in range(2,length+1): + for j in range((length-1)//3+2): + if j==0: + #adding a at the end + mat[i][j][0]=mat[i-1][j][0]+mat[i-1][j][1]+mat[i-1][j][3] + + #adding b at the end + mat[i][j][1]=mat[i-1][j][0] + mat[i][j][2]=mat[i-1][j][1] + + #adding any other lowercase character + mat[i][j][3]=mat[i-1][j][0]*24+mat[i-1][j][1]*24+mat[i-1][j][2]*25+mat[i-1][j][3]*25 + + elif 3*j+1> 1 - if i <= mid: - update(p << 1, l, mid, i, v) + mid = (left+right)>>1 + if target <= mid: + update(pos<<1, left, mid, target, vertex) else: - update((p << 1) | 1, mid + 1, r, i, v) - tree[p] = max(tree[p << 1], tree[(p << 1) | 1]) + update((pos<<1)|1, mid+1, right, target, vertex) + tree[pos] = max_seq(tree[pos<<1], tree[(pos<<1)|1]) - def get_max(p, l, r, s, e): - if l > e or r < s: + def get_max(pos, left, right, start, end): + if left > end or right < start: return 0 - if l >= s and r <= e: - return tree[p] - mid = (l+r) >> 1 - return max(get_max(p << 1, l, mid, s, e), get_max((p << 1) | 1, mid+1, r, s, e)) + if left >= start and right <= end: + return tree[pos] + mid = (left+right)>>1 + return max_seq(get_max(pos<<1, left, mid, start, end), + get_max((pos<<1)|1, mid+1, right, start, end)) ans = 0 - for x in sequence: - cur = get_max(1, 0, mx, 0, x-1)+1 - ans = max(ans, cur) - update(1, 0, mx, x, cur) + for element in sequence: + cur = get_max(1, 0, max_seq, 0, element-1)+1 + ans = max_seq(ans, cur) + update(1, 0, max_seq, element, cur) return ans @@ -85,32 +86,32 @@ def longest_increasing_subsequence_optimized2(sequence): type sequence: list[int] rtype: int """ - n = len(sequence) - tree = [0] * (n << 2) + length = len(sequence) + tree = [0] * (length<<2) sorted_seq = sorted((x, -i) for i, x in enumerate(sequence)) - - def update(p, l, r, i, v): - if l == r: - tree[p] = v + def update(pos, left, right, target, vertex): + if left == right: + tree[pos] = vertex return - mid = (l+r) >> 1 - if i <= mid: - update(p << 1, l, mid, i, v) + mid = (left+right)>>1 + if target <= mid: + vertex(pos<<1, left, mid, target, vertex) else: - update((p << 1) | 1, mid+1, r, i, v) - tree[p] = max(tree[p << 1], tree[(p << 1) | 1]) + vertex((pos<<1)|1, mid+1, right, target, vertex) + tree[pos] = max(tree[pos<<1], tree[(pos<<1)|1]) - def get_max(p, l, r, s, e): - if l > e or r < s: + def get_max(pos, left, right, start, end): + if left > end or right < start: return 0 - if l >= s and r <= e: - return tree[p] - mid = (l+r) >> 1 - return max(get_max(p << 1, l, mid, s, e), get_max((p << 1) | 1, mid+1, r, s, e)) + if left >= start and right <= end: + return tree[pos] + mid = (left+right)>>1 + return max(get_max(pos<<1, left, mid, start, end), + get_max((pos<<1)|1, mid+1, right, start, end)) ans = 0 - for x, j in sorted_seq: - i = -j - cur = get_max(1, 0, n-1, 0, i-1)+1 + for tup in sorted_seq: + i = -tup[1] + cur = get_max(1, 0, length-1, 0, i-1)+1 ans = max(ans, cur) - update(1, 0, n-1, i, cur) + update(1, 0, length-1, i, cur) return ans diff --git a/algorithms/dp/matrix_chain_order.py b/algorithms/dp/matrix_chain_order.py index 47386f66f..dd2ef7bd9 100644 --- a/algorithms/dp/matrix_chain_order.py +++ b/algorithms/dp/matrix_chain_order.py @@ -8,6 +8,10 @@ def matrix_chain_order(array): + """Finds optimal order to multiply matrices + + array -- int[] + """ n = len(array) matrix = [[0 for x in range(n)] for x in range(n)] sol = [[0 for x in range(n)] for x in range(n)] @@ -24,10 +28,15 @@ def matrix_chain_order(array): return matrix, sol # Print order of matrix with Ai as matrix +def print_optimal_solution(optimal_solution,i,j): + """Print the solution -def print_optimal_solution(optimal_solution, i, j): - if i == j: - print("A" + str(i), end=" ") + optimal_solution -- int[][] + i -- int[] + j -- int[] + """ + if i==j: + print("A" + str(i),end = " ") else: print("(", end=" ") print_optimal_solution(optimal_solution, i, optimal_solution[i][j]) @@ -36,15 +45,17 @@ def print_optimal_solution(optimal_solution, i, j): def main(): - array = [30, 35, 15, 5, 10, 20, 25] - n = len(array) - # Size of matrix created from above array will be + """ + Testing for matrix_chain_ordering + """ + array=[30,35,15,5,10,20,25] + length=len(array) + #Size of matrix created from above array will be # 30*35 35*15 15*5 5*10 10*20 20*25 matrix, optimal_solution = matrix_chain_order(array) - print("No. of Operation required: "+str((matrix[1][n-1]))) - print_optimal_solution(optimal_solution, 1, n-1) - + print("No. of Operation required: "+str((matrix[1][length-1]))) + print_optimal_solution(optimal_solution,1,length-1) if __name__ == '__main__': main() diff --git a/algorithms/dp/max_product_subarray.py b/algorithms/dp/max_product_subarray.py index 592e98fb1..7a9beac63 100644 --- a/algorithms/dp/max_product_subarray.py +++ b/algorithms/dp/max_product_subarray.py @@ -14,15 +14,15 @@ def max_product(nums): :rtype: int """ lmin = lmax = gmax = nums[0] - for i in range(len(nums)): - t1 = nums[i] * lmax - t2 = nums[i] * lmin - lmax = max(max(t1, t2), nums[i]) - lmin = min(min(t1, t2), nums[i]) + for num in nums: + t_1 = num * lmax + t_2 = num * lmin + lmax = max(max(t_1, t_2), num) + lmin = min(min(t_1, t_2), num) gmax = max(gmax, lmax) -''' +""" Another approach that would print max product and the subarray Examples: @@ -34,18 +34,18 @@ def max_product(nums): #=> max_product_so_far: 24, [-4, -3, -2, -1] subarray_with_max_product([-3,0,1]) #=> max_product_so_far: 1, [1] -''' +""" def subarray_with_max_product(arr): ''' arr is list of positive/negative numbers ''' - l = len(arr) + length = len(arr) product_so_far = max_product_end = 1 max_start_i = 0 so_far_start_i = so_far_end_i = 0 all_negative_flag = True - for i in range(l): + for i in range(length): max_product_end *= arr[i] if arr[i] > 0: all_negative_flag = False @@ -60,8 +60,7 @@ def subarray_with_max_product(arr): so_far_start_i = max_start_i if all_negative_flag: - print("max_product_so_far: %s, %s" % - (reduce(lambda x, y: x * y, arr), arr)) + print(f"max_product_so_far: {reduce(lambda x, y: x * y, arr)}, {arr}") + else: - print("max_product_so_far: %s, %s" % - (product_so_far, arr[so_far_start_i:so_far_end_i + 1])) + print(f"max_product_so_far: {product_so_far},{arr[so_far_start_i:so_far_end_i + 1]}") diff --git a/algorithms/dp/min_cost_path.py b/algorithms/dp/min_cost_path.py index 356489e9a..7771e1e0f 100644 --- a/algorithms/dp/min_cost_path.py +++ b/algorithms/dp/min_cost_path.py @@ -27,29 +27,32 @@ def min_cost(cost): + """Find minimum cost. - n = len(cost) + Keyword arguments: + cost -- matrix containing costs + """ + length = len(cost) # dist[i] stores minimum cost from 0 --> i. - dist = [INF] * n + dist = [INF] * length dist[0] = 0 # cost from 0 --> 0 is zero. - for i in range(n): - for j in range(i+1, n): + for i in range(length): + for j in range(i+1,length): dist[j] = min(dist[j], dist[i] + cost[i][j]) - return dist[n-1] + return dist[length-1] if __name__ == '__main__': + costs = [ [ 0, 15, 80, 90], # cost[i][j] is the cost of + [-1, 0, 40, 50], # going from i --> j + [-1, -1, 0, 70], + [-1, -1, -1, 0] ] # cost[i][j] = -1 for i > j + TOTAL_LEN = len(costs) - cost = [[0, 15, 80, 90], # cost[i][j] is the cost of - [-1, 0, 40, 50], # going from i --> j - [-1, -1, 0, 70], - [-1, -1, -1, 0]] # cost[i][j] = -1 for i > j - total_len = len(cost) - - mcost = min_cost(cost) + mcost = min_cost(costs) assert mcost == 65 - print("The Minimum cost to reach station %d is %d" % (total_len, mcost)) + print(f"The minimum cost to reach station {TOTAL_LEN} is {mcost}") diff --git a/algorithms/dp/num_decodings.py b/algorithms/dp/num_decodings.py index 541db6edf..87cd3e3dc 100644 --- a/algorithms/dp/num_decodings.py +++ b/algorithms/dp/num_decodings.py @@ -17,33 +17,37 @@ """ -def num_decodings(s): +def num_decodings(enc_mes): """ :type s: str :rtype: int """ - if not s or s[0] == "0": + if not enc_mes or enc_mes[0] == "0": return 0 - wo_last, wo_last_two = 1, 1 - for i in range(1, len(s)): - x = wo_last if s[i] != "0" else 0 - y = wo_last_two if int(s[i-1:i+1]) < 27 and s[i-1] != "0" else 0 - wo_last_two = wo_last - wo_last = x+y - return wo_last + last_char, last_two_chars = 1, 1 + for i in range(1, len(enc_mes)): + last = last_char if enc_mes[i] != "0" else 0 + last_two = last_two_chars if int(enc_mes[i-1:i+1]) < 27 and enc_mes[i-1] != "0" else 0 + last_two_chars = last_char + last_char = last+last_two + return last_char -def num_decodings2(s): - if not s or s.startswith('0'): +def num_decodings2(enc_mes): + """ + :type s: str + :rtype: int + """ + if not enc_mes or enc_mes.startswith('0'): return 0 stack = [1, 1] - for i in range(1, len(s)): - if s[i] == '0': - if s[i-1] == '0' or s[i-1] > '2': + for i in range(1, len(enc_mes)): + if enc_mes[i] == '0': + if enc_mes[i-1] == '0' or enc_mes[i-1] > '2': # only '10', '20' is valid return 0 stack.append(stack[-2]) - elif 9 < int(s[i-1:i+1]) < 27: + elif 9 < int(enc_mes[i-1:i+1]) < 27: # '01 - 09' is not allowed stack.append(stack[-2]+stack[-1]) else: diff --git a/algorithms/dp/planting_trees.py b/algorithms/dp/planting_trees.py index 56b99cde7..ee8394b8e 100644 --- a/algorithms/dp/planting_trees.py +++ b/algorithms/dp/planting_trees.py @@ -1,26 +1,25 @@ """ -An even number of trees are left along one side of a country road. -You've been assigned the job to plant these trees at an even interval on -both sides of the road. The length L and width W of the road are variable, -and a pair of trees must be planted at the beginning (at 0) -and at the end (at L) of the road. Only one tree can be moved at a time. -The goal is to calculate the lowest amount of distance that the trees -have to be moved before they are all in a valid position. +An even number of trees are left along one side of a country road. You've been +assigned the job to plant these trees at an even interval on both sides of the +road. The length and width of the road are variable, and a pair of trees must +be planted at the beginning (at 0) and at the end (at length) of the road. Only +one tree can be moved at a time. The goal is to calculate the lowest amount of +distance that the trees have to be moved before they are all in a valid +position. """ from math import sqrt - -def planting_trees(trees, L, W): +def planting_trees(trees, length, width): """ Returns the minimum distance that trees have to be moved before they are all in a valid state. Parameters: tree (list): A sorted list of integers with all trees' - position along the road. - L (int): An integer with the length of the road. - W (int): An integer with the width of the road. + position along the road. + length (int): An integer with the length of the road. + width (int): An integer with the width of the road. Returns: A float number with the total distance trees have been moved. @@ -29,21 +28,22 @@ def planting_trees(trees, L, W): n_pairs = int(len(trees)/2) - space_between_pairs = L/(n_pairs-1) + space_between_pairs = length/(n_pairs-1) target_locations = [location*space_between_pairs for location in range(n_pairs)] cmatrix = [[0 for _ in range(n_pairs+1)] for _ in range(n_pairs+1)] - for ri in range(1, n_pairs+1): - cmatrix[ri][0] = cmatrix[ri-1][0] + sqrt(W + abs(trees[ri]-target_locations[ri-1])**2) - for li in range(1, n_pairs+1): - cmatrix[0][li] = cmatrix[0][li-1] + abs(trees[li]-target_locations[li-1]) - - for ri in range(1, n_pairs+1): - for li in range(1, n_pairs+1): - cmatrix[ri][li] = min( - cmatrix[ri-1][li] + sqrt(W + (trees[li + ri]-target_locations[ri-1])**2), - cmatrix[ri][li-1] + abs(trees[li + ri]-target_locations[li-1]) + for r_i in range(1, n_pairs+1): + cmatrix[r_i][0] = cmatrix[r_i-1][0] + sqrt( + width + abs(trees[r_i]-target_locations[r_i-1])**2) + for l_i in range(1, n_pairs+1): + cmatrix[0][l_i] = cmatrix[0][l_i-1] + abs(trees[l_i]-target_locations[l_i-1]) + + for r_i in range(1, n_pairs+1): + for l_i in range(1, n_pairs+1): + cmatrix[r_i][l_i] = min( + cmatrix[r_i-1][l_i] + sqrt(width + (trees[l_i + r_i]-target_locations[r_i-1])**2), + cmatrix[r_i][l_i-1] + abs(trees[l_i + r_i]-target_locations[l_i-1]) ) return cmatrix[n_pairs][n_pairs] diff --git a/algorithms/dp/regex_matching.py b/algorithms/dp/regex_matching.py index 72311d557..3b65e3594 100644 --- a/algorithms/dp/regex_matching.py +++ b/algorithms/dp/regex_matching.py @@ -18,91 +18,44 @@ is_match("ab", ".*") → true is_match("aab", "c*a*b") → true """ -import unittest -class Solution(object): - def is_match(self, s, p): - m, n = len(s) + 1, len(p) + 1 - matches = [[False] * n for _ in range(m)] - - # Match empty string with empty pattern - matches[0][0] = True - - # Match empty string with .* - for i, element in enumerate(p[1:], 2): - matches[0][i] = matches[0][i - 2] and element == '*' - - for i, ss in enumerate(s, 1): - for j, pp in enumerate(p, 1): - if pp != '*': - # The previous character has matched and the current one - # has to be matched. Two possible matches: the same or . - matches[i][j] = matches[i - 1][j - 1] and \ - (ss == pp or pp == '.') - else: - # Horizontal look up [j - 2]. - # Not use the character before *. - matches[i][j] |= matches[i][j - 2] - - # Vertical look up [i - 1]. - # Use at least one character before *. - # p a b * - # s 1 0 0 0 - # a 0 1 0 1 - # b 0 0 1 1 - # b 0 0 0 ? - if ss == p[j - 2] or p[j - 2] == '.': - matches[i][j] |= matches[i - 1][j] - - return matches[-1][-1] - -class TestSolution(unittest.TestCase): - def test_none_0(self): - s = "" - p = "" - self.assertTrue(Solution().is_match(s, p)) - - def test_none_1(self): - s = "" - p = "a" - self.assertFalse(Solution().is_match(s, p)) - - def test_no_symbol_equal(self): - s = "abcd" - p = "abcd" - self.assertTrue(Solution().is_match(s, p)) - - def test_no_symbol_not_equal_0(self): - s = "abcd" - p = "efgh" - self.assertFalse(Solution().is_match(s, p)) - - def test_no_symbol_not_equal_1(self): - s = "ab" - p = "abb" - self.assertFalse(Solution().is_match(s, p)) - - def test_symbol_0(self): - s = "" - p = "a*" - self.assertTrue(Solution().is_match(s, p)) - - def test_symbol_1(self): - s = "a" - p = "ab*" - self.assertTrue(Solution().is_match(s, p)) - - def test_symbol_2(self): - # E.g. - # s a b b - # p 1 0 0 0 - # a 0 1 0 0 - # b 0 0 1 0 - # * 0 1 1 1 - s = "abb" - p = "ab*" - self.assertTrue(Solution().is_match(s, p)) - - -if __name__ == "__main__": - unittest.main() +def is_match(str_a, str_b): + """Finds if `str_a` matches `str_b` + + Keyword arguments: + str_a -- string + str_b -- string + """ + len_a, len_b = len(str_a) + 1, len(str_b) + 1 + matches = [[False] * len_b for _ in range(len_a)] + + # Match empty string with empty pattern + matches[0][0] = True + + # Match empty string with .* + for i, element in enumerate(str_b[1:], 2): + matches[0][i] = matches[0][i - 2] and element == '*' + + for i, char_a in enumerate(str_a, 1): + for j, char_b in enumerate(str_b, 1): + if char_b != '*': + # The previous character has matched and the current one + # has to be matched. Two possible matches: the same or . + matches[i][j] = matches[i - 1][j - 1] and \ + char_b in (char_a, '.') + else: + # Horizontal look up [j - 2]. + # Not use the character before *. + matches[i][j] |= matches[i][j - 2] + + # Vertical look up [i - 1]. + # Use at least one character before *. + # p a b * + # s 1 0 0 0 + # a 0 1 0 1 + # b 0 0 1 1 + # b 0 0 0 ? + if char_a == str_b[j - 2] or str_b[j - 2] == '.': + matches[i][j] |= matches[i - 1][j] + + return matches[-1][-1] diff --git a/algorithms/dp/rod_cut.py b/algorithms/dp/rod_cut.py index b4a82245e..d9259e862 100644 --- a/algorithms/dp/rod_cut.py +++ b/algorithms/dp/rod_cut.py @@ -1,24 +1,28 @@ -# A Dynamic Programming solution for Rod cutting problem +"""A Dynamic Programming solution for Rod cutting problem +""" + INT_MIN = -32767 - -# Returns the best obtainable price for a rod of length n and -# price[] as prices of different pieces + def cut_rod(price): + """ + Returns the best obtainable price for a rod of length n and + price[] as prices of different pieces + """ n = len(price) val = [0]*(n+1) - + # Build the table val[] in bottom up manner and return # the last entry from the table for i in range(1, n+1): max_val = INT_MIN for j in range(i): - max_val = max(max_val, price[j] + val[i-j-1]) + max_val = max(max_val, price[j] + val[i-j-1]) val[i] = max_val - + return val[n] - + # Driver program to test above functions arr = [1, 5, 8, 9, 10, 17, 17, 20] print("Maximum Obtainable Value is " + str(cut_rod(arr))) - + # This code is contributed by Bhavya Jain diff --git a/algorithms/dp/word_break.py b/algorithms/dp/word_break.py index ea244dc68..f520456b0 100644 --- a/algorithms/dp/word_break.py +++ b/algorithms/dp/word_break.py @@ -1,44 +1,41 @@ """ Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, -determine if s can be segmented into a space-separated +determine if word can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words. For example, given -s = "leetcode", +word = "leetcode", dict = ["leet", "code"]. Return true because "leetcode" can be segmented as "leet code". -""" - -""" -s = abc word_dict = ["a","bc"] +word = abc word_dict = ["a","bc"] True False False False """ # TC: O(N^2) SC: O(N) -def word_break(s, word_dict): +def word_break(word, word_dict): """ - :type s: str + :type word: str :type word_dict: Set[str] :rtype: bool """ - dp = [False] * (len(s)+1) - dp[0] = True - for i in range(1, len(s)+1): + dp_array = [False] * (len(word)+1) + dp_array[0] = True + for i in range(1, len(word)+1): for j in range(0, i): - if dp[j] and s[j:i] in word_dict: - dp[i] = True + if dp_array[j] and word[j:i] in word_dict: + dp_array[i] = True break - return dp[-1] + return dp_array[-1] if __name__ == "__main__": - s = "keonkim" + STR = "keonkim" dic = ["keon", "kim"] - print(word_break(s, dic)) + print(word_break(str, dic)) diff --git a/algorithms/graph/__init__.py b/algorithms/graph/__init__.py index 3bf3a1c8c..1f52f9bdb 100644 --- a/algorithms/graph/__init__.py +++ b/algorithms/graph/__init__.py @@ -1,3 +1,7 @@ +""" +Collection of algorithms on graphs. +""" + from .tarjan import * from .check_bipartite import * from .maximum_flow import * diff --git a/algorithms/graph/all_pairs_shortest_path.py b/algorithms/graph/all_pairs_shortest_path.py index 46f3b7c09..d8e6feca3 100644 --- a/algorithms/graph/all_pairs_shortest_path.py +++ b/algorithms/graph/all_pairs_shortest_path.py @@ -7,22 +7,36 @@ example -a = [[0, 0.1, 0.101, 0.142, 0.277], [0.465, 0, 0.191, 0.192, 0.587], [0.245, 0.554, 0, 0.333, 0.931], [1.032, 0.668, 0.656, 0, 0.151], [0.867, 0.119, 0.352, 0.398, 0]] +a = [[0 , 0.1 , 0.101, 0.142, 0.277], + [0.465, 0 , 0.191, 0.192, 0.587], + [0.245, 0.554, 0 , 0.333, 0.931], + [1.032, 0.668, 0.656, 0 , 0.151], + [0.867, 0.119, 0.352, 0.398, 0]] -result +result -[[0, 0.1, 0.101, 0.142, 0.277], [0.436, 0, 0.191, 0.192, 0.34299999999999997], [0.245, 0.345, 0, 0.333, 0.484], [0.706, 0.27, 0.46099999999999997, 0, 0.151], [0.5549999999999999, 0.119, 0.31, 0.311, 0]] +[[0 , 0.1 , 0.101, 0.142, 0.277], + [0.436, 0 , 0.191, 0.192, 0.343], + [0.245, 0.345, 0 , 0.333, 0.484], + [0.706, 0.27 , 0.461, 0 , 0.151], + [0.555, 0.119, 0.31 , 0.311, 0]] """ import copy def all_pairs_shortest_path(adjacency_matrix): + """ + Given a matrix of the edge weights between respective nodes, returns a + matrix containing the shortest distance distance between the two nodes. + """ + new_array = copy.deepcopy(adjacency_matrix) - for k in range(len(new_array)): - for i in range(len(new_array)): - for j in range(len(new_array)): + size = len(new_array) + for k in range(size): + for i in range(size): + for j in range(size): if new_array[i][j] > new_array[i][k] + new_array[k][j]: - new_array[i][j] = new_array[i][k] + new_array[k][j] - - return new_array \ No newline at end of file + new_array[i][j] = new_array[i][k] + new_array[k][j] + + return new_array diff --git a/algorithms/graph/bellman_ford.py b/algorithms/graph/bellman_ford.py index 518f75c4b..ea1e0465b 100644 --- a/algorithms/graph/bellman_ford.py +++ b/algorithms/graph/bellman_ford.py @@ -1,26 +1,29 @@ -''' -This Bellman-Ford Code is for determination whether we can get -shortest path from given graph or not for single-source shortest-paths problem. -In other words, if given graph has any negative-weight cycle that is reachable -from the source, then it will give answer False for "no solution exits". -For argument graph, it should be a dictionary type -such as -graph = { - 'a': {'b': 6, 'e': 7}, - 'b': {'c': 5, 'd': -4, 'e': 8}, - 'c': {'b': -2}, - 'd': {'a': 2, 'c': 7}, - 'e': {'b': -3} -} -''' +""" +Determination of single-source shortest-path. +""" def bellman_ford(graph, source): + """ + This Bellman-Ford Code is for determination whether we can get + shortest path from given graph or not for single-source shortest-paths problem. + In other words, if given graph has any negative-weight cycle that is reachable + from the source, then it will give answer False for "no solution exits". + For argument graph, it should be a dictionary type + such as + graph = { + 'a': {'b': 6, 'e': 7}, + 'b': {'c': 5, 'd': -4, 'e': 8}, + 'c': {'b': -2}, + 'd': {'a': 2, 'c': 7}, + 'e': {'b': -3} + } + """ weight = {} pre_node = {} initialize_single_source(graph, source, weight, pre_node) - for i in range(1, len(graph)): + for _ in range(1, len(graph)): for node in graph: for adjacent in graph[node]: if weight[adjacent] > weight[node] + graph[node][adjacent]: @@ -35,10 +38,11 @@ def bellman_ford(graph, source): return True def initialize_single_source(graph, source, weight, pre_node): - + """ + Initialize data structures for Bellman-Ford algorithm. + """ for node in graph: weight[node] = float('inf') pre_node[node] = None weight[source] = 0 - diff --git a/algorithms/graph/check_bipartite.py b/algorithms/graph/check_bipartite.py index dacc003b3..51a84ab4c 100644 --- a/algorithms/graph/check_bipartite.py +++ b/algorithms/graph/check_bipartite.py @@ -1,39 +1,40 @@ """ - Bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets. (https://en.wikipedia.org/wiki/Bipartite_graph) - -Time complexity is O(|E|) -Space complexity is O(|V|) - """ def check_bipartite(adj_list): + """ + Determine if the given graph is bipartite. - V = len(adj_list) + Time complexity is O(|E|) + Space complexity is O(|V|) + """ - # Divide vertexes in the graph into set_type 1 and 2 + vertices = len(adj_list) + + # Divide vertexes in the graph into set_type 0 and 1 # Initialize all set_types as -1 - set_type = [-1 for v in range(V)] + set_type = [-1 for v in range(vertices)] set_type[0] = 0 - q = [0] + queue = [0] - while q: - v = q.pop(0) + while queue: + current = queue.pop(0) # If there is a self-loop, it cannot be bipartite - if adj_list[v][v]: + if adj_list[current][current]: return False - for u in range(V): - if adj_list[v][u]: - if set_type[u] == set_type[v]: + for adjacent in range(vertices): + if adj_list[current][adjacent]: + if set_type[adjacent] == set_type[current]: return False - elif set_type[u] == -1: + + if set_type[adjacent] == -1: # set type of u opposite of v - set_type[u] = 1 - set_type[v] - q.append(u) + set_type[adjacent] = 1 - set_type[current] + queue.append(adjacent) return True - diff --git a/algorithms/graph/check_digraph_strongly_connected.py b/algorithms/graph/check_digraph_strongly_connected.py index 25ae80cd2..03dd6ab79 100644 --- a/algorithms/graph/check_digraph_strongly_connected.py +++ b/algorithms/graph/check_digraph_strongly_connected.py @@ -1,53 +1,69 @@ +""" +In a directed graph, a strongly connected component is a set of vertices such +that for any pairs of vertices u and v there exists a path (u-...-v) that +connects them. A graph is strongly connected if it is a single strongly +connected component. +""" + from collections import defaultdict class Graph: - def __init__(self,v): - self.v = v - self.graph = defaultdict(list) - - def add_edge(self,u,v): - self.graph[u].append(v) - - def dfs(self): - visited = [False] * self.v - self.dfs_util(0,visited) - if visited == [True]*self.v: - return True - return False - - def dfs_util(self,i,visited): - visited[i] = True - for u in self.graph[i]: - if not(visited[u]): - self.dfs_util(u,visited) - - def reverse_graph(self): - g = Graph(self.v) - for i in range(len(self.graph)): - for j in self.graph[i]: - g.add_edge(j,i) - return g - - - def is_sc(self): - if self.dfs(): - gr = self.reverse_graph() - if gr.dfs(): - return True - return False - - -g1 = Graph(5) -g1.add_edge(0, 1) -g1.add_edge(1, 2) -g1.add_edge(2, 3) -g1.add_edge(3, 0) -g1.add_edge(2, 4) -g1.add_edge(4, 2) -print ("Yes") if g1.is_sc() else print("No") - -g2 = Graph(4) -g2.add_edge(0, 1) -g2.add_edge(1, 2) -g2.add_edge(2, 3) -print ("Yes") if g2.is_sc() else print("No") + """ + A directed graph where edges are one-way (a two-way edge can be represented by using two edges). + """ + + def __init__(self,vertex_count): + """ + Create a new graph with vertex_count vertices. + """ + + self.vertex_count = vertex_count + self.graph = defaultdict(list) + + def add_edge(self,source,target): + """ + Add an edge going from source to target + """ + self.graph[source].append(target) + + def dfs(self): + """ + Determine if all nodes are reachable from node 0 + """ + visited = [False] * self.vertex_count + self.dfs_util(0,visited) + if visited == [True]*self.vertex_count: + return True + return False + + def dfs_util(self,source,visited): + """ + Determine if all nodes are reachable from the given node + """ + visited[source] = True + for adjacent in self.graph[source]: + if not visited[adjacent]: + self.dfs_util(adjacent,visited) + + def reverse_graph(self): + """ + Create a new graph where every edge a->b is replaced with an edge b->a + """ + reverse_graph = Graph(self.vertex_count) + for source, adjacent in self.graph.items(): + for target in adjacent: + # Note: we reverse the order of arguments + # pylint: disable=arguments-out-of-order + reverse_graph.add_edge(target,source) + return reverse_graph + + + def is_strongly_connected(self): + """ + Determine if the graph is strongly connected. + """ + if self.dfs(): + reversed_graph = self.reverse_graph() + if reversed_graph.dfs(): + return True + return False diff --git a/algorithms/graph/clone_graph.py b/algorithms/graph/clone_graph.py index 0fbae1d43..84d0324cf 100644 --- a/algorithms/graph/clone_graph.py +++ b/algorithms/graph/clone_graph.py @@ -1,4 +1,4 @@ -""" +r""" Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. @@ -29,69 +29,95 @@ import collections -# Definition for a undirected graph node class UndirectedGraphNode: - def __init__(self, x): - self.label = x + """ + A node in an undirected graph. Contains a label and a list of neighbouring + nodes (initially empty). + """ + + def __init__(self, label): + self.label = label self.neighbors = [] + def shallow_copy(self): + """ + Return a shallow copy of this node (ignoring any neighbors) + """ + return UndirectedGraphNode(self.label) + + def add_neighbor(self, node): + """ + Adds a new neighbor + """ + self.neighbors.append(node) + -# BFS def clone_graph1(node): + """ + Returns a new graph as seen from the given node using a breadth first search (BFS). + """ if not node: - return - node_copy = UndirectedGraphNode(node.label) + return None + node_copy = node.shallow_copy() dic = {node: node_copy} queue = collections.deque([node]) while queue: node = queue.popleft() for neighbor in node.neighbors: if neighbor not in dic: # neighbor is not visited - neighbor_copy = UndirectedGraphNode(neighbor.label) + neighbor_copy = neighbor.shallow_copy() dic[neighbor] = neighbor_copy - dic[node].neighbors.append(neighbor_copy) + dic[node].add_neighbor(neighbor_copy) queue.append(neighbor) else: - dic[node].neighbors.append(dic[neighbor]) + dic[node].add_neighbor(dic[neighbor]) return node_copy -# DFS iteratively def clone_graph2(node): + """ + Returns a new graph as seen from the given node using an iterative depth first search (DFS). + """ if not node: - return - node_copy = UndirectedGraphNode(node.label) + return None + node_copy = node.shallow_copy() dic = {node: node_copy} stack = [node] while stack: node = stack.pop() for neighbor in node.neighbors: if neighbor not in dic: - neighbor_copy = UndirectedGraphNode(neighbor.label) + neighbor_copy = neighbor.shallow_copy() dic[neighbor] = neighbor_copy - dic[node].neighbors.append(neighbor_copy) + dic[node].add_neighbor(neighbor_copy) stack.append(neighbor) else: - dic[node].neighbors.append(dic[neighbor]) + dic[node].add_neighbor(dic[neighbor]) return node_copy -# DFS recursively def clone_graph(node): + """ + Returns a new graph as seen from the given node using a recursive depth first search (DFS). + """ if not node: - return - node_copy = UndirectedGraphNode(node.label) + return None + node_copy = node.shallow_copy() dic = {node: node_copy} dfs(node, dic) return node_copy def dfs(node, dic): + """ + Clones a graph using a recursive depth first search. Stores the clones in + the dictionary, keyed by the original nodes. + """ for neighbor in node.neighbors: if neighbor not in dic: - neighbor_copy = UndirectedGraphNode(neighbor.label) + neighbor_copy = neighbor.shallow_copy() dic[neighbor] = neighbor_copy - dic[node].neighbors.append(neighbor_copy) + dic[node].add_neighbor(neighbor_copy) dfs(neighbor, dic) else: - dic[node].neighbors.append(dic[neighbor]) + dic[node].add_neighbor(dic[neighbor]) diff --git a/algorithms/graph/count_connected_number_of_component.py b/algorithms/graph/count_connected_number_of_component.py index a944cf096..a58eda6c3 100644 --- a/algorithms/graph/count_connected_number_of_component.py +++ b/algorithms/graph/count_connected_number_of_component.py @@ -1,7 +1,7 @@ #count connected no of component using DFS ''' -In graph theory, a component, sometimes called a connected component, -of an undirected graph is a subgraph in which any +In graph theory, a component, sometimes called a connected component, +of an undirected graph is a subgraph in which any two vertices are connected to each other by paths. Example: @@ -19,16 +19,16 @@ # Code is Here -def dfs(source,visited,l): +def dfs(source,visited,adjacency_list): ''' Function that performs DFS ''' visited[source] = True - for child in l[source]: + for child in adjacency_list[source]: if not visited[child]: - dfs(child,visited,l) - -def count_components(l,size): - ''' + dfs(child,visited,adjacency_list) + +def count_components(adjacency_list,size): + ''' Function that counts the Connected components on bases of DFS. return type : int ''' @@ -37,18 +37,23 @@ def count_components(l,size): visited = [False]*(size+1) for i in range(1,size+1): if not visited[i]: - dfs(i,visited,l) + dfs(i,visited,adjacency_list) count+=1 - return count + return count + +def main(): + """ + Example application + """ + node_count,edge_count = map(int, input("Enter the Number of Nodes and Edges \n").split(' ')) + adjacency = [[] for _ in range(node_count+1)] + for _ in range(edge_count): + print("Enter the edge's Nodes in form of `source target`\n") + source,target = map(int,input().split(' ')) + adjacency[source].append(target) + adjacency[target].append(source) + print("Total number of Connected Components are : ", count_components(adjacency,node_count)) - # Driver code if __name__ == '__main__': - n,m = map(int, input("Enter the Number of Nodes and Edges \n").split(' ')) - l = [[] for _ in range(n+1)] - for i in range(m): - print("Enter the edge's Nodes in form of a b\n") - a,b = map(int,input().split(' ')) - l[a].append(b) - l[b].append(a) - print("Total number of Connected Components are : ", count_components(l,n)) + main() diff --git a/algorithms/graph/cycle_detection.py b/algorithms/graph/cycle_detection.py index 61cf61c1f..0821b1c0a 100644 --- a/algorithms/graph/cycle_detection.py +++ b/algorithms/graph/cycle_detection.py @@ -9,27 +9,22 @@ class TraversalState(Enum): + """ + For a given node: + - WHITE: has not been visited yet + - GRAY: is currently being investigated for a cycle + - BLACK: is not part of a cycle + """ WHITE = 0 GRAY = 1 BLACK = 2 - -example_graph_with_cycle = {'A': ['B', 'C'], - 'B': ['D'], - 'C': ['F'], - 'D': ['E', 'F'], - 'E': ['B'], - 'F': []} - -example_graph_without_cycle = {'A': ['B', 'C'], - 'B': ['D', 'E'], - 'C': ['F'], - 'D': ['E'], - 'E': [], - 'F': []} - - def is_in_cycle(graph, traversal_states, vertex): + """ + Determines if the given vertex is in a cycle. + + :param: traversal_states: for each vertex, the state it is in + """ if traversal_states[vertex] == TraversalState.GRAY: return True traversal_states[vertex] = TraversalState.GRAY @@ -41,12 +36,20 @@ def is_in_cycle(graph, traversal_states, vertex): def contains_cycle(graph): + """ + Determines if there is a cycle in the given graph. + The graph should be given as a dictionary: + + graph = {'A': ['B', 'C'], + 'B': ['D'], + 'C': ['F'], + 'D': ['E', 'F'], + 'E': ['B'], + 'F': []} + """ traversal_states = {vertex: TraversalState.WHITE for vertex in graph} for vertex, state in traversal_states.items(): if (state == TraversalState.WHITE and is_in_cycle(graph, traversal_states, vertex)): return True return False - -print(contains_cycle(example_graph_with_cycle)) -print(contains_cycle(example_graph_without_cycle)) diff --git a/algorithms/graph/dijkstra.py b/algorithms/graph/dijkstra.py index 2cf043072..e5022e3af 100644 --- a/algorithms/graph/dijkstra.py +++ b/algorithms/graph/dijkstra.py @@ -1,36 +1,49 @@ -#Dijkstra's single source shortest path algorithm +""" +Dijkstra's single-source shortest-path algorithm +""" class Dijkstra(): + """ + A fully connected directed graph with edge weights + """ - def __init__(self, vertices): - self.vertices = vertices - self.graph = [[0 for column in range(vertices)] for row in range(vertices)] + def __init__(self, vertex_count): + self.vertex_count = vertex_count + self.graph = [[0 for _ in range(vertex_count)] for _ in range(vertex_count)] def min_distance(self, dist, min_dist_set): + """ + Find the vertex that is closest to the visited set + """ min_dist = float("inf") - for v in range(self.vertices): - if dist[v] < min_dist and min_dist_set[v] == False: - min_dist = dist[v] - min_index = v + for target in range(self.vertex_count): + if min_dist_set[target]: + continue + if dist[target] < min_dist: + min_dist = dist[target] + min_index = target return min_index def dijkstra(self, src): - - dist = [float("inf")] * self.vertices + """ + Given a node, returns the shortest distance to every other node + """ + dist = [float("inf")] * self.vertex_count dist[src] = 0 - min_dist_set = [False] * self.vertices - - for count in range(self.vertices): + min_dist_set = [False] * self.vertex_count + for _ in range(self.vertex_count): #minimum distance vertex that is not processed - u = self.min_distance(dist, min_dist_set) + source = self.min_distance(dist, min_dist_set) #put minimum distance vertex in shortest tree - min_dist_set[u] = True + min_dist_set[source] = True #Update dist value of the adjacent vertices - for v in range(self.vertices): - if self.graph[u][v] > 0 and min_dist_set[v] == False and dist[v] > dist[u] + self.graph[u][v]: - dist[v] = dist[u] + self.graph[u][v] + for target in range(self.vertex_count): + if self.graph[source][target] <= 0 or min_dist_set[target]: + continue + if dist[target] > dist[source] + self.graph[source][target]: + dist[target] = dist[source] + self.graph[source][target] return dist diff --git a/algorithms/graph/find_all_cliques.py b/algorithms/graph/find_all_cliques.py index 10f7a24eb..f1db16ed5 100644 --- a/algorithms/graph/find_all_cliques.py +++ b/algorithms/graph/find_all_cliques.py @@ -1,12 +1,19 @@ -# takes dict of sets -# each key is a vertex -# value is set of all edges connected to vertex -# returns list of lists (each sub list is a maximal clique) -# implementation of the basic algorithm described in: -# Bron, Coen; Kerbosch, Joep (1973), "Algorithm 457: finding all cliques of an undirected graph", - +""" +Finds all cliques in an undirected graph. A clique is a set of vertices in the +graph such that the subgraph is fully connected (ie. for any pair of nodes in +the subgraph there is an edge between them). +""" def find_all_cliques(edges): + """ + takes dict of sets + each key is a vertex + value is set of all edges connected to vertex + returns list of lists (each sub list is a maximal clique) + implementation of the basic algorithm described in: + Bron, Coen; Kerbosch, Joep (1973), "Algorithm 457: finding all cliques of an undirected graph", + """ + def expand_clique(candidates, nays): nonlocal compsub if not candidates and not nays: diff --git a/algorithms/graph/find_path.py b/algorithms/graph/find_path.py index a18800555..253e43ca3 100644 --- a/algorithms/graph/find_path.py +++ b/algorithms/graph/find_path.py @@ -1,14 +1,14 @@ -myGraph = {'A': ['B', 'C'], - 'B': ['C', 'D'], - 'C': ['D', 'F'], - 'D': ['C'], - 'E': ['F'], - 'F': ['C']} +""" +Functions for finding paths in graphs. +""" -# find path from start to end using recursion with backtracking +# pylint: disable=dangerous-default-value def find_path(graph, start, end, path=[]): + """ + Find a path between two nodes using recursion and backtracking. + """ path = path + [start] - if (start == end): + if start == end: return path if not start in graph: return None @@ -18,13 +18,16 @@ def find_path(graph, start, end, path=[]): return newpath return None -# find all path +# pylint: disable=dangerous-default-value def find_all_path(graph, start, end, path=[]): + """ + Find all paths between two nodes using recursion and backtracking + """ path = path + [start] - if (start == end): + if start == end: return [path] if not start in graph: - return None + return [] paths = [] for node in graph[start]: if node not in path: @@ -34,6 +37,9 @@ def find_all_path(graph, start, end, path=[]): return paths def find_shortest_path(graph, start, end, path=[]): + """ + find the shortest path between two nodes + """ path = path + [start] if start == end: return path @@ -47,6 +53,3 @@ def find_shortest_path(graph, start, end, path=[]): if not shortest or len(newpath) < len(shortest): shortest = newpath return shortest - -print(find_all_path(myGraph, 'A', 'F')) -# print(find_shortest_path(myGraph, 'A', 'D')) diff --git a/algorithms/graph/graph.py b/algorithms/graph/graph.py index 31e564599..5d4305933 100644 --- a/algorithms/graph/graph.py +++ b/algorithms/graph/graph.py @@ -3,24 +3,31 @@ It can be shared across graph algorithms. """ -class Node(object): +class Node: + """ + A node/vertex in a graph. + """ + def __init__(self, name): self.name = name @staticmethod def get_name(obj): + """ + Return the name of the node + """ if isinstance(obj, Node): return obj.name - elif isinstance(obj, str): + if isinstance(obj, str): return obj return'' - + def __eq__(self, obj): return self.name == self.get_name(obj) def __repr__(self): return self.name - + def __hash__(self): return hash(self.name) @@ -42,72 +49,63 @@ def __ge__(self, obj): def __bool__(self): return self.name -class DirectedEdge(object): +class DirectedEdge: + """ + A directed edge in a directed graph. + Stores the source and target node of the edge. + """ + def __init__(self, node_from, node_to): - self.nf = node_from - self.nt = node_to + self.source = node_from + self.target = node_to def __eq__(self, obj): if isinstance(obj, DirectedEdge): - return obj.nf == self.nf and obj.nt == self.nt + return obj.source == self.source and obj.target == self.target return False - + def __repr__(self): - return '({0} -> {1})'.format(self.nf, self.nt) + return f"({self.source} -> {self.target})" + +class DirectedGraph: + """ + A directed graph. + Stores a set of nodes, edges and adjacency matrix. + """ -class DirectedGraph(object): + # pylint: disable=dangerous-default-value def __init__(self, load_dict={}): self.nodes = [] self.edges = [] - self.adjmt = {} + self.adjacency_list = {} - if load_dict and type(load_dict) == dict: - for v in load_dict: - node_from = self.add_node(v) - self.adjmt[node_from] = [] - for w in load_dict[v]: - node_to = self.add_node(w) - self.adjmt[node_from].append(node_to) - self.add_edge(v, w) + if load_dict and isinstance(load_dict, dict): + for vertex in load_dict: + node_from = self.add_node(vertex) + self.adjacency_list[node_from] = [] + for neighbor in load_dict[vertex]: + node_to = self.add_node(neighbor) + self.adjacency_list[node_from].append(node_to) + self.add_edge(vertex, neighbor) def add_node(self, node_name): + """ + Add a new named node to the graph. + """ try: return self.nodes[self.nodes.index(node_name)] except ValueError: node = Node(node_name) self.nodes.append(node) return node - + def add_edge(self, node_name_from, node_name_to): + """ + Add a new edge to the graph between two nodes. + """ try: node_from = self.nodes[self.nodes.index(node_name_from)] node_to = self.nodes[self.nodes.index(node_name_to)] self.edges.append(DirectedEdge(node_from, node_to)) except ValueError: pass - -class Graph: - def __init__(self, vertices): - # No. of vertices - self.V = vertices - - # default dictionary to store graph - self.graph = {} - - # To store transitive closure - self.tc = [[0 for j in range(self.V)] for i in range(self.V)] - - # function to add an edge to graph - def add_edge(self, u, v): - if u in self.graph: - self.graph[u].append(v) - else: - self.graph[u] = [v] - -#g = Graph(4) -#g.add_edge(0, 1) -#g.add_edge(0, 2) -#g.add_edge(1, 2) -#g.add_edge(2, 0) -#g.add_edge(2, 3) -#g.add_edge(3, 3) diff --git a/algorithms/graph/markov_chain.py b/algorithms/graph/markov_chain.py index c588311d2..78c50bd12 100644 --- a/algorithms/graph/markov_chain.py +++ b/algorithms/graph/markov_chain.py @@ -1,26 +1,39 @@ -import random +""" +Implements a markov chain. Chains are described using a dictionary: + + my_chain = { + 'A': {'A': 0.6, + 'E': 0.4}, + 'E': {'A': 0.7, + 'E': 0.3} + } +""" -my_chain = { - 'A': {'A': 0.6, - 'E': 0.4}, - 'E': {'A': 0.7, - 'E': 0.3} -} +import random def __choose_state(state_map): + """ + Choose the next state randomly + """ choice = random.random() probability_reached = 0 for state, probability in state_map.items(): probability_reached += probability if probability_reached > choice: return state + return None def next_state(chain, current_state): + """ + Given a markov-chain, randomly chooses the next state given the current state. + """ next_state_map = chain.get(current_state) - next_state = __choose_state(next_state_map) - return next_state + return __choose_state(next_state_map) def iterating_markov_chain(chain, state): + """ + Yield a sequence of states given a markov chain and the initial state + """ while True: state = next_state(chain, state) yield state diff --git a/algorithms/graph/maximum_flow.py b/algorithms/graph/maximum_flow.py index ca7824482..b46e70790 100644 --- a/algorithms/graph/maximum_flow.py +++ b/algorithms/graph/maximum_flow.py @@ -8,16 +8,22 @@ If there is no edge from i to j, capacity[i][j] should be zero. """ -import queue +from queue import Queue +# pylint: disable=too-many-arguments def dfs(capacity, flow, visit, vertices, idx, sink, current_flow = 1 << 63): + """ + Depth First Search implementation for Ford-Fulkerson algorithm. + """ + # DFS function for ford_fulkerson algorithm. - if idx == sink: + if idx == sink: return current_flow visit[idx] = True for nxt in range(vertices): if not visit[nxt] and flow[idx][nxt] < capacity[idx][nxt]: - tmp = dfs(capacity, flow, visit, vertices, nxt, sink, min(current_flow, capacity[idx][nxt]-flow[idx][nxt])) + available_flow = min(current_flow, capacity[idx][nxt]-flow[idx][nxt]) + tmp = dfs(capacity, flow, visit, vertices, nxt, sink, available_flow) if tmp: flow[idx][nxt] += tmp flow[nxt][idx] -= tmp @@ -25,38 +31,42 @@ def dfs(capacity, flow, visit, vertices, idx, sink, current_flow = 1 << 63): return 0 def ford_fulkerson(capacity, source, sink): - # Computes maximum flow from source to sink using DFS. - # Time Complexity : O(Ef) - # E is the number of edges and f is the maximum flow in the graph. + """ + Computes maximum flow from source to sink using DFS. + Time Complexity : O(Ef) + E is the number of edges and f is the maximum flow in the graph. + """ vertices = len(capacity) ret = 0 - flow = [[0]*vertices for i in range(vertices)] + flow = [[0]*vertices for _ in range(vertices)] while True: - visit = [False for i in range(vertices)] + visit = [False for _ in range(vertices)] tmp = dfs(capacity, flow, visit, vertices, source, sink) - if tmp: + if tmp: ret += tmp - else: + else: break return ret def edmonds_karp(capacity, source, sink): - # Computes maximum flow from source to sink using BFS. - # Time complexity : O(V*E^2) - # V is the number of vertices and E is the number of edges. + """ + Computes maximum flow from source to sink using BFS. + Time complexity : O(V*E^2) + V is the number of vertices and E is the number of edges. + """ vertices = len(capacity) ret = 0 - flow = [[0]*vertices for i in range(vertices)] + flow = [[0]*vertices for _ in range(vertices)] while True: tmp = 0 - q = queue.Queue() - visit = [False for i in range(vertices)] - par = [-1 for i in range(vertices)] + queue = Queue() + visit = [False for _ in range(vertices)] + par = [-1 for _ in range(vertices)] visit[source] = True - q.put((source, 1 << 63)) + queue.put((source, 1 << 63)) # Finds new flow using BFS. - while q.qsize(): - front = q.get() + while queue.qsize(): + front = queue.get() idx, current_flow = front if idx == sink: tmp = current_flow @@ -65,8 +75,8 @@ def edmonds_karp(capacity, source, sink): if not visit[nxt] and flow[idx][nxt] < capacity[idx][nxt]: visit[nxt] = True par[nxt] = idx - q.put((nxt, min(current_flow, capacity[idx][nxt]-flow[idx][nxt]))) - if par[sink] == -1: + queue.put((nxt, min(current_flow, capacity[idx][nxt]-flow[idx][nxt]))) + if par[sink] == -1: break ret += tmp parent = par[sink] @@ -80,31 +90,35 @@ def edmonds_karp(capacity, source, sink): return ret def dinic_bfs(capacity, flow, level, source, sink): - # BFS function for Dinic algorithm. - # Check whether sink is reachable only using edges that is not full. - + """ + BFS function for Dinic algorithm. + Check whether sink is reachable only using edges that is not full. + """ vertices = len(capacity) - q = queue.Queue() - q.put(source) + queue = Queue() + queue.put(source) level[source] = 0 - while q.qsize(): - front = q.get() + while queue.qsize(): + front = queue.get() for nxt in range(vertices): if level[nxt] == -1 and flow[front][nxt] < capacity[front][nxt]: level[nxt] = level[front] + 1 - q.put(nxt) + queue.put(nxt) return level[sink] != -1 def dinic_dfs(capacity, flow, level, idx, sink, work, current_flow = 1 << 63): - # DFS function for Dinic algorithm. - # Finds new flow using edges that is not full. + """ + DFS function for Dinic algorithm. + Finds new flow using edges that is not full. + """ if idx == sink: return current_flow vertices = len(capacity) while work[idx] < vertices: nxt = work[idx] if level[nxt] == level[idx] + 1 and flow[idx][nxt] < capacity[idx][nxt]: - tmp = dinic_dfs(capacity, flow, level, nxt, sink, work, min(current_flow, capacity[idx][nxt] - flow[idx][nxt])) + available_flow = min(current_flow, capacity[idx][nxt] - flow[idx][nxt]) + tmp = dinic_dfs(capacity, flow, level, nxt, sink, work, available_flow) if tmp > 0: flow[idx][nxt] += tmp flow[nxt][idx] -= tmp @@ -113,9 +127,11 @@ def dinic_dfs(capacity, flow, level, idx, sink, work, current_flow = 1 << 63): return 0 def dinic(capacity, source, sink): - # Computes maximum flow from source to sink using Dinic algorithm. - # Time complexity : O(V^2*E) - # V is the number of vertices and E is the number of edges. + """ + Computes maximum flow from source to sink using Dinic algorithm. + Time complexity : O(V^2*E) + V is the number of vertices and E is the number of edges. + """ vertices = len(capacity) flow = [[0]*vertices for i in range(vertices)] ret = 0 @@ -131,4 +147,3 @@ def dinic(capacity, source, sink): else: break return ret - diff --git a/algorithms/graph/maximum_flow_bfs.py b/algorithms/graph/maximum_flow_bfs.py index 4d2d032ff..bd056c8d3 100644 --- a/algorithms/graph/maximum_flow_bfs.py +++ b/algorithms/graph/maximum_flow_bfs.py @@ -9,12 +9,12 @@ example -graph = [[0, 16, 13, 0, 0, 0], - [0, 0, 10, 12, 0, 0], - [0, 4, 0, 0, 14, 0], - [0, 0, 9, 0, 0, 20], - [0, 0, 0, 7, 0, 4], - [0, 0, 0, 0, 0, 0]] +graph = [[0, 16, 13, 0, 0, 0], + [0, 0, 10, 12, 0, 0], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], + [0, 0, 0, 7, 0, 4], + [0, 0, 0, 0, 0, 0]] answer should be @@ -26,27 +26,30 @@ import math def maximum_flow_bfs(adjacency_matrix): + """ + Get the maximum flow through a graph using a breadth first search + """ #initial setting new_array = copy.deepcopy(adjacency_matrix) total = 0 - while(1): + while True: #setting min to max_value - min = math.inf + min_flow = math.inf #save visited nodes visited = [0]*len(new_array) #save parent nodes path = [0]*len(new_array) - + #initialize queue for BFS bfs = queue.Queue() - #initial setting + #initial setting visited[0] = 1 bfs.put(0) #BFS to find path - while(bfs.qsize() > 0): + while bfs.qsize() > 0: #pop from queue src = bfs.get() for k in range(len(new_array)): @@ -56,29 +59,29 @@ def maximum_flow_bfs(adjacency_matrix): visited[k] = 1 bfs.put(k) path[k] = src - + #if there is no path from src to sink - if(visited[len(new_array) - 1] == 0): + if visited[len(new_array) - 1] == 0: break - + #initial setting tmp = len(new_array) - 1 #Get minimum flow - while(tmp != 0): + while tmp != 0: #find minimum flow - if(min > new_array[path[tmp]][tmp]): - min = new_array[path[tmp]][tmp] + if min_flow > new_array[path[tmp]][tmp]: + min_flow = new_array[path[tmp]][tmp] tmp = path[tmp] #initial setting tmp = len(new_array) - 1 #reduce capacity - while(tmp != 0): - new_array[path[tmp]][tmp] = new_array[path[tmp]][tmp] - min + while tmp != 0: + new_array[path[tmp]][tmp] = new_array[path[tmp]][tmp] - min_flow tmp = path[tmp] - total = total + min - + total = total + min_flow + return total diff --git a/algorithms/graph/maximum_flow_dfs.py b/algorithms/graph/maximum_flow_dfs.py index 2d89d6b56..e27c4e851 100644 --- a/algorithms/graph/maximum_flow_dfs.py +++ b/algorithms/graph/maximum_flow_dfs.py @@ -9,12 +9,12 @@ example -graph = [[0, 16, 13, 0, 0, 0], - [0, 0, 10, 12, 0, 0], - [0, 4, 0, 0, 14, 0], - [0, 0, 9, 0, 0, 20], - [0, 0, 0, 7, 0, 4], - [0, 0, 0, 0, 0, 0]] +graph = [[0, 16, 13, 0, 0, 0], + [0, 0, 10, 12, 0, 0], + [0, 4, 0, 0, 14, 0], + [0, 0, 9, 0, 0, 20], + [0, 0, 0, 7, 0, 4], + [0, 0, 0, 0, 0, 0]] answer should be @@ -25,48 +25,52 @@ import math def maximum_flow_dfs(adjacency_matrix): + """ + Get the maximum flow through a graph using a depth first search + """ + #initial setting new_array = copy.deepcopy(adjacency_matrix) total = 0 - while(1): + while True: #setting min to max_value min = math.inf #save visited nodes visited = [0]*len(new_array) #save parent nodes path = [0]*len(new_array) - + #initialize stack for DFS stack = [] - #initial setting + #initial setting visited[0] = 1 stack.append(0) #DFS to find path - while(len(stack) > 0): + while len(stack) > 0: #pop from queue src = stack.pop() for k in range(len(new_array)): #checking capacity and visit - if(new_array[src][k] > 0 and visited[k] == 0 ): + if new_array[src][k] > 0 and visited[k] == 0: #if not, put into queue and chage to visit and save path visited[k] = 1 stack.append(k) path[k] = src - + #if there is no path from src to sink - if(visited[len(new_array) - 1] == 0): + if visited[len(new_array) - 1] == 0: break - + #initial setting tmp = len(new_array) - 1 #Get minimum flow - while(tmp != 0): + while tmp != 0: #find minimum flow - if(min > new_array[path[tmp]][tmp]): + if min > new_array[path[tmp]][tmp]: min = new_array[path[tmp]][tmp] tmp = path[tmp] @@ -74,11 +78,11 @@ def maximum_flow_dfs(adjacency_matrix): tmp = len(new_array) - 1 #reduce capacity - while(tmp != 0): + while tmp != 0: new_array[path[tmp]][tmp] = new_array[path[tmp]][tmp] - min tmp = path[tmp] total = total + min - + return total - \ No newline at end of file + diff --git a/algorithms/graph/minimum_spanning_tree.py b/algorithms/graph/minimum_spanning_tree.py index dcc6898b6..d53a957ca 100644 --- a/algorithms/graph/minimum_spanning_tree.py +++ b/algorithms/graph/minimum_spanning_tree.py @@ -1,130 +1,151 @@ -# Minimum spanning tree (MST) is going to use an undirected graph -# -# The disjoint set is represented with an list of integers where -# is the parent of the node at position . -# If = , it's a root, or a head, of a set +""" +Minimum spanning tree (MST) is going to use an undirected graph +""" +import sys +# pylint: disable=too-few-public-methods class Edge: - def __init__(self, u, v, weight): - self.u = u - self.v = v + """ + An edge of an undirected graph + """ + + def __init__(self, source, target, weight): + self.source = source + self.target = target self.weight = weight class DisjointSet: - def __init__(self, n): - # Args: - # n (int): Number of vertices in the graph - - self.parent = [None] * n # Contains wich node is the parent of the node at poisition - self.size = [1] * n # Contains size of node at index , used to optimize merge - for i in range(n): + """ + The disjoint set is represented with an list of integers where + is the parent of the node at position . + If = , it's a root, or a head, of a set + """ + + def __init__(self, size): + """ + Args: + n (int): Number of vertices in the graph + """ + + self.parent = [None] * size # Contains wich node is the parent of the node at poisition + self.size = [1] * size # Contains size of node at index , used to optimize merge + for i in range(size): self.parent[i] = i # Make all nodes his own parent, creating n sets. - def merge_set(self, a, b): - # Args: - # a, b (int): Indexes of nodes whose sets will be merged. + def merge_set(self, node1, node2): + """ + Args: + node1, node2 (int): Indexes of nodes whose sets will be merged. + """ # Get the set of nodes at position
and # If and are the roots, this will be constant O(1) - a = self.find_set(a) - b = self.find_set(b) + node1 = self.find_set(node1) + node2 = self.find_set(node2) # Join the shortest node to the longest, minimizing tree size (faster find) - if self.size[a] < self.size[b]: - self.parent[a] = b # Merge set(a) and set(b) - self.size[b] += self.size[a] # Add size of old set(a) to set(b) + if self.size[node1] < self.size[node2]: + self.parent[node1] = node2 # Merge set(a) and set(b) + self.size[node2] += self.size[node1] # Add size of old set(a) to set(b) else: - self.parent[b] = a # Merge set(b) and set(a) - self.size[a] += self.size[b] # Add size of old set(b) to set(a) - - def find_set(self, a): - if self.parent[a] != a: - # Very important, memoize result of the + self.parent[node2] = node1 # Merge set(b) and set(a) + self.size[node1] += self.size[node2] # Add size of old set(b) to set(a) + + def find_set(self, node): + """ + Get the root element of the set containing + """ + if self.parent[node] != node: + # Very important, memoize result of the # recursion in the list to optimize next # calls and make this operation practically constant, O(1) - self.parent[a] = self.find_set(self.parent[a]) + self.parent[node] = self.find_set(self.parent[node]) # node it's the set root, so we can return that index - return self.parent[a] - - -def kruskal(n, edges, ds): - # Args: - # n (int): Number of vertices in the graph - # edges (list of Edge): Edges of the graph - # ds (DisjointSet): DisjointSet of the vertices - # Returns: - # int: sum of weights of the minnimum spanning tree - # - # Kruskal algorithm: - # This algorithm will find the optimal graph with less edges and less - # total weight to connect all vertices (MST), the MST will always contain - # n-1 edges because it's the minimum required to connect n vertices. - # - # Procedure: - # Sort the edges (criteria: less weight). - # Only take edges of nodes in different sets. - # If we take a edge, we need to merge the sets to discard these. - # After repeat this until select n-1 edges, we will have the complete MST. + return self.parent[node] + + +def kruskal(vertex_count, edges, forest): + """ + Args: + vertex_count (int): Number of vertices in the graph + edges (list of Edge): Edges of the graph + forest (DisjointSet): DisjointSet of the vertices + Returns: + int: sum of weights of the minnimum spanning tree + + Kruskal algorithm: + This algorithm will find the optimal graph with less edges and less + total weight to connect all vertices (MST), the MST will always contain + n-1 edges because it's the minimum required to connect n vertices. + + Procedure: + Sort the edges (criteria: less weight). + Only take edges of nodes in different sets. + If we take a edge, we need to merge the sets to discard these. + After repeat this until select n-1 edges, we will have the complete MST. + """ edges.sort(key=lambda edge: edge.weight) mst = [] # List of edges taken, minimum spanning tree for edge in edges: - set_u = ds.find_set(edge.u) # Set of the node - set_v = ds.find_set(edge.v) # Set of the node + set_u = forest.find_set(edge.u) # Set of the node + set_v = forest.find_set(edge.v) # Set of the node if set_u != set_v: - ds.merge_set(set_u, set_v) + forest.merge_set(set_u, set_v) mst.append(edge) - if len(mst) == n-1: - # If we have selected n-1 edges, all the other + if len(mst) == vertex_count-1: + # If we have selected n-1 edges, all the other # edges will be discarted, so, we can stop here break return sum([edge.weight for edge in mst]) - - -if __name__ == "__main__": - # Test. How input works: - # Input consists of different weighted, connected, undirected graphs. - # line 1: - # integers n, m - # lines 2..m+2: - # edge with the format -> node index u, node index v, integer weight - # - # Samples of input: - # - # 5 6 - # 1 2 3 - # 1 3 8 - # 2 4 5 - # 3 4 2 - # 3 5 4 - # 4 5 6 - # - # 3 3 - # 2 1 20 - # 3 1 20 - # 2 3 100 - # - # Sum of weights of the optimal paths: - # 14, 40 - import sys - for n_m in sys.stdin: - n, m = map(int, n_m.split()) - ds = DisjointSet(m) - edges = [None] * m # Create list of size +def main(): + """ + Test. How input works: + Input consists of different weighted, connected, undirected graphs. + line 1: + integers n, m + lines 2..m+2: + edge with the format -> node index u, node index v, integer weight + + Samples of input: + + 5 6 + 1 2 3 + 1 3 8 + 2 4 5 + 3 4 2 + 3 5 4 + 4 5 6 + + 3 3 + 2 1 20 + 3 1 20 + 2 3 100 + + Sum of weights of the optimal paths: + 14, 40 + """ + for size in sys.stdin: + vertex_count, edge_count = map(int, size.split()) + forest = DisjointSet(edge_count) + edges = [None] * edge_count # Create list of size # Read edges from input - for i in range(m): - u, v, weight = map(int, input().split()) - u -= 1 # Convert from 1-indexed to 0-indexed - v -= 1 # Convert from 1-indexed to 0-indexed - edges[i] = Edge(u, v, weight) + for i in range(edge_count): + source, target, weight = map(int, input().split()) + source -= 1 # Convert from 1-indexed to 0-indexed + target -= 1 # Convert from 1-indexed to 0-indexed + edges[i] = Edge(source, target, weight) # After finish input and graph creation, use Kruskal algorithm for MST: - print("MST weights sum:", kruskal(n, edges, ds)) + print("MST weights sum:", kruskal(vertex_count, edges, forest)) + +if __name__ == "__main__": + main() diff --git a/algorithms/graph/path_between_two_vertices_in_digraph.py b/algorithms/graph/path_between_two_vertices_in_digraph.py index f85513320..4bf290253 100644 --- a/algorithms/graph/path_between_two_vertices_in_digraph.py +++ b/algorithms/graph/path_between_two_vertices_in_digraph.py @@ -1,52 +1,51 @@ +""" +Determine if there is a path between nodes in a graph +""" + from collections import defaultdict class Graph: - def __init__(self, v): - self.v = v - self.graph = defaultdict(list) - self.has_path = False - - def add_edge(self, u, v): - self.graph[u].append(v) - - def dfs(self, x, y): - visited = [False] * self.v - self.dfsutil(visited, x, y,) - - def dfsutil(self, visited, x, y): - visited[x] = True - for i in self.graph[x]: - if y in self.graph[x]: - self.has_path = True - return - if(not(visited[i])): - self.dfsutil(visited, x, i) - - def is_reachable(self, x, y): - self.has_path = False - self.dfs(x, y) - return self.has_path - - -# Create a graph given in the above diagram -g = Graph(4) -g.add_edge(0, 1) -g.add_edge(0, 2) -g.add_edge(1, 2) -g.add_edge(2, 0) -g.add_edge(2, 3) -g.add_edge(3, 3) - -u, v = 1, 3 - -if g.is_reachable(u, v): - print("There is a path from %d to %d" % (u, v)) -else: - print("There is no path from %d to %d" % (u, v)) - -u, v = 1, 3 -if g.is_reachable(u, v): - print("There is a path from %d to %d" % (u, v)) -else: - print("There is no path from %d to %d" % (u, v)) + """ + A directed graph + """ + + def __init__(self,vertex_count): + self.vertex_count = vertex_count + self.graph = defaultdict(list) + self.has_path = False + + def add_edge(self,source,target): + """ + Add a new directed edge to the graph + """ + self.graph[source].append(target) + + def dfs(self,source,target): + """ + Determine if there is a path from source to target using a depth first search + """ + visited = [False] * self.vertex_count + self.dfsutil(visited,source,target,) + + def dfsutil(self,visited,source,target): + """ + Determine if there is a path from source to target using a depth first search. + :param: visited should be an array of booleans determining if the + corresponding vertex has been visited already + """ + visited[source] = True + for i in self.graph[source]: + if target in self.graph[source]: + self.has_path = True + return + if not visited[i]: + self.dfsutil(visited,source,i) + + def is_reachable(self,source,target): + """ + Determine if there is a path from source to target + """ + self.has_path = False + self.dfs(source,target) + return self.has_path diff --git a/algorithms/graph/prims_minimum_spanning.py b/algorithms/graph/prims_minimum_spanning.py index 02295c4c2..af7cb4357 100644 --- a/algorithms/graph/prims_minimum_spanning.py +++ b/algorithms/graph/prims_minimum_spanning.py @@ -1,15 +1,15 @@ ''' This Prim's Algorithm Code is for finding weight of minimum spanning tree of a connected graph. -For argument graph, it should be a dictionary type -such as -graph = { - 'a': [ [3, 'b'], [8,'c'] ], - 'b': [ [3, 'a'], [5, 'd'] ], - 'c': [ [8, 'a'], [2, 'd'], [4, 'e'] ], - 'd': [ [5, 'b'], [2, 'c'], [6, 'e'] ], - 'e': [ [4, 'c'], [6, 'd'] ] -} +For argument graph, it should be a dictionary type such as: + + graph = { + 'a': [ [3, 'b'], [8,'c'] ], + 'b': [ [3, 'a'], [5, 'd'] ], + 'c': [ [8, 'a'], [2, 'd'], [4, 'e'] ], + 'd': [ [5, 'b'], [2, 'c'], [6, 'e'] ], + 'e': [ [4, 'c'], [6, 'd'] ] + } where 'a','b','c','d','e' are nodes (these can be 1,2,3,4,5 as well) ''' @@ -17,26 +17,26 @@ import heapq # for priority queue -# prim's algo. to find weight of minimum spanning tree def prims_minimum_spanning(graph_used): + """ + Prim's algorithm to find weight of minimum spanning tree + """ vis=[] - s=[[0,1]] - prim = [] + heap=[[0,1]] + prim = set() mincost=0 - - while(len(s)>0): - v=heapq.heappop(s) - x=v[1] - if(x in vis): + + while len(heap) > 0: + cost, node = heapq.heappop(heap) + if node in vis: continue - mincost += v[0] - prim.append(x) - vis.append(x) + mincost += cost + prim.add(node) + vis.append(node) - for j in graph_used[x]: - i=j[-1] - if(i not in vis): - heapq.heappush(s,j) + for distance, adjacent in graph_used[node]: + if adjacent not in vis: + heapq.heappush(heap, [distance, adjacent]) return mincost diff --git a/algorithms/graph/satisfiability.py b/algorithms/graph/satisfiability.py index bc1d1892e..0cae8ee92 100644 --- a/algorithms/graph/satisfiability.py +++ b/algorithms/graph/satisfiability.py @@ -1,45 +1,49 @@ -''' +""" Given a formula in conjunctive normal form (2-CNF), finds a way to assign True/False values to all variables to satisfy all clauses, or reports there is no solution. https://en.wikipedia.org/wiki/2-satisfiability -''' -''' Format: +Format: - each clause is a pair of literals - each literal in the form (name, is_neg) where name is an arbitrary identifier, and is_neg is true if the literal is negated -''' -formula = [(('x', False), ('y', False)), - (('y', True), ('y', True)), - (('a', False), ('b', False)), - (('a', True), ('c', True)), - (('c', False), ('b', True))] +""" +def dfs_transposed(vertex, graph, order, visited): + """ + Perform a depth first search traversal of the graph starting at the given vertex. + Stores the order in which nodes were visited to the list, in transposed order. + """ + visited[vertex] = True -def dfs_transposed(v, graph, order, vis): - vis[v] = True + for adjacent in graph[vertex]: + if not visited[adjacent]: + dfs_transposed(adjacent, graph, order, visited) - for u in graph[v]: - if not vis[u]: - dfs_transposed(u, graph, order, vis) + order.append(vertex) - order.append(v) +def dfs(vertex, current_comp, vertex_scc, graph, visited): + """ + Perform a depth first search traversal of the graph starting at the given vertex. + Records all visited nodes as being of a certain strongly connected component. + """ + visited[vertex] = True + vertex_scc[vertex] = current_comp -def dfs(v, current_comp, vertex_scc, graph, vis): - vis[v] = True - vertex_scc[v] = current_comp - - for u in graph[v]: - if not vis[u]: - dfs(u, current_comp, vertex_scc, graph, vis) + for adjacent in graph[vertex]: + if not visited[adjacent]: + dfs(adjacent, current_comp, vertex_scc, graph, visited) def add_edge(graph, vertex_from, vertex_to): + """ + Add a directed edge to the graph. + """ if vertex_from not in graph: graph[vertex_from] = [] @@ -49,26 +53,26 @@ def add_edge(graph, vertex_from, vertex_to): def scc(graph): ''' Computes the strongly connected components of a graph ''' order = [] - vis = {vertex: False for vertex in graph} + visited = {vertex: False for vertex in graph} graph_transposed = {vertex: [] for vertex in graph} - for (v, neighbours) in graph.iteritems(): - for u in neighbours: - add_edge(graph_transposed, u, v) + for (source, neighbours) in graph.iteritems(): + for target in neighbours: + add_edge(graph_transposed, target, source) - for v in graph: - if not vis[v]: - dfs_transposed(v, graph_transposed, order, vis) + for vertex in graph: + if not visited[vertex]: + dfs_transposed(vertex, graph_transposed, order, visited) - vis = {vertex: False for vertex in graph} + visited = {vertex: False for vertex in graph} vertex_scc = {} current_comp = 0 - for v in reversed(order): - if not vis[v]: + for vertex in reversed(order): + if not visited[vertex]: # Each dfs will visit exactly one component - dfs(v, current_comp, vertex_scc, graph, vis) + dfs(vertex, current_comp, vertex_scc, graph, visited) current_comp += 1 return vertex_scc @@ -91,6 +95,9 @@ def build_graph(formula): def solve_sat(formula): + """ + Solves the 2-SAT problem + """ graph = build_graph(formula) vertex_scc = scc(graph) @@ -119,8 +126,20 @@ def solve_sat(formula): return value -if __name__ == '__main__': +def main(): + """ + Entry point for testing + """ + formula = [(('x', False), ('y', False)), + (('y', True), ('y', True)), + (('a', False), ('b', False)), + (('a', True), ('c', True)), + (('c', False), ('b', True))] + result = solve_sat(formula) - for (variable, assign) in result.iteritems(): - print("{}:{}".format(variable, assign)) + for (variable, assign) in result.items(): + print(f"{variable}:{assign}") + +if __name__ == '__main__': + main() diff --git a/algorithms/graph/tarjan.py b/algorithms/graph/tarjan.py index 399a39d6d..ebc69326c 100644 --- a/algorithms/graph/tarjan.py +++ b/algorithms/graph/tarjan.py @@ -6,7 +6,11 @@ from algorithms.graph.graph import DirectedGraph -class Tarjan(object): +# pylint: disable=too-few-public-methods +class Tarjan: + """ + A directed graph used for finding strongly connected components + """ def __init__(self, dict_graph): self.graph = DirectedGraph(dict_graph) self.index = 0 @@ -14,44 +18,48 @@ def __init__(self, dict_graph): # Runs Tarjan # Set all node index to None - for v in self.graph.nodes: - v.index = None + for vertex in self.graph.nodes: + vertex.index = None self.sccs = [] - for v in self.graph.nodes: - if v.index is None: - self.strongconnect(v, self.sccs) + for vertex in self.graph.nodes: + if vertex.index is None: + self.strongconnect(vertex, self.sccs) - def strongconnect(self, v, sccs): + def strongconnect(self, vertex, sccs): + """ + Given a vertex, adds all successors of the given vertex to the same connected component + """ # Set the depth index for v to the smallest unused index - v.index = self.index - v.lowlink = self.index + vertex.index = self.index + vertex.lowlink = self.index self.index += 1 - self.stack.append(v) - v.on_stack = True + self.stack.append(vertex) + vertex.on_stack = True # Consider successors of v - for w in self.graph.adjmt[v]: - if w.index is None: + for adjacent in self.graph.adjacency_list[vertex]: + if adjacent.index is None: # Successor w has not yet been visited; recurse on it - self.strongconnect(w, sccs) - v.lowlink = min(v.lowlink, w.lowlink) - elif w.on_stack: + self.strongconnect(adjacent, sccs) + vertex.lowlink = min(vertex.lowlink, adjacent.lowlink) + elif adjacent.on_stack: # Successor w is in stack S and hence in the current SCC - # If w is not on stack, then (v, w) is a cross-edge in the DFS tree and must be ignored + # If w is not on stack, then (v, w) is a cross-edge in the DFS + # tree and must be ignored # Note: The next line may look odd - but is correct. # It says w.index not w.lowlink; that is deliberate and from the original paper - v.lowlink = min(v.lowlink, w.index) + vertex.lowlink = min(vertex.lowlink, adjacent.index) # If v is a root node, pop the stack and generate an SCC - if v.lowlink == v.index: + if vertex.lowlink == vertex.index: # start a new strongly connected component scc = [] while True: - w = self.stack.pop() - w.on_stack = False - scc.append(w) - if w == v: + adjacent = self.stack.pop() + adjacent.on_stack = False + scc.append(adjacent) + if adjacent == vertex: break scc.sort() sccs.append(scc) diff --git a/algorithms/graph/transitive_closure_dfs.py b/algorithms/graph/transitive_closure_dfs.py index 655c75c89..ca7e43a1b 100644 --- a/algorithms/graph/transitive_closure_dfs.py +++ b/algorithms/graph/transitive_closure_dfs.py @@ -1,52 +1,55 @@ -# This class represents a directed graph using adjacency +""" +Finds the transitive closure of a graph. + +reference: https://en.wikipedia.org/wiki/Transitive_closure#In_graph_theory +""" + class Graph: + """ + This class represents a directed graph using adjacency lists + """ def __init__(self, vertices): # No. of vertices - self.V = vertices + self.vertex_count = vertices # default dictionary to store graph self.graph = {} # To store transitive closure - self.tc = [[0 for j in range(self.V)] for i in range(self.V)] - - # function to add an edge to graph - def add_edge(self, u, v): - if u in self.graph: - self.graph[u].append(v) + self.closure = [[0 for j in range(vertices)] for i in range(vertices)] + + def add_edge(self, source, target): + """ + Adds a directed edge to the graph + """ + if source in self.graph: + self.graph[source].append(target) else: - self.graph[u] = [v] + self.graph[source] = [target] - # A recursive DFS traversal function that finds - # all reachable vertices for s - def dfs_util(self, s, v): + def dfs_util(self, source, target): + """ + A recursive DFS traversal function that finds + all reachable vertices for source + """ - # Mark reachability from s to v as true. - self.tc[s][v] = 1 + # Mark reachability from source to target as true. + self.closure[source][target] = 1 - # Find all the vertices reachable through v - for i in self.graph[v]: - if self.tc[s][i] == 0: - self.dfs_util(s, i) + # Find all the vertices reachable through target + for adjacent in self.graph[target]: + if self.closure[source][adjacent] == 0: + self.dfs_util(source, adjacent) - # The function to find transitive closure. It uses - # recursive dfs_util() def transitive_closure(self): + """ + The function to find transitive closure. It uses + recursive dfs_util() + """ # Call the recursive helper function to print DFS # traversal starting from all vertices one by one - for i in range(self.V): + for i in range(self.vertex_count): self.dfs_util(i, i) - print(self.tc) - - -# g = Graph(4) -# g.add_edge(0, 1) -# g.add_edge(0, 2) -# g.add_edge(1, 2) -# g.add_edge(2, 0) -# g.add_edge(2, 3) -# g.add_edge(3, 3) -# print("Transitive closure matrix is") -# g.transitive_closure() + return self.closure diff --git a/algorithms/graph/traversal.py b/algorithms/graph/traversal.py index cbfc65ff4..19ae14154 100644 --- a/algorithms/graph/traversal.py +++ b/algorithms/graph/traversal.py @@ -1,9 +1,6 @@ -graph = {'A': set(['B', 'C', 'F']), - 'B': set(['A', 'D', 'E']), - 'C': set(['A', 'F']), - 'D': set(['B']), - 'E': set(['B', 'F']), - 'F': set(['A', 'C', 'E'])} +""" +Different ways to traverse a graph +""" # dfs and bfs are the ultimately same except that they are visiting nodes in # different order. To simulate this ordering we would use stack for dfs and @@ -11,56 +8,41 @@ # def dfs_traverse(graph, start): + """ + Traversal by depth first search. + """ visited, stack = set(), [start] while stack: node = stack.pop() if node not in visited: visited.add(node) - for nextNode in graph[node]: - if nextNode not in visited: - stack.append(nextNode) + for next_node in graph[node]: + if next_node not in visited: + stack.append(next_node) return visited -# print(dfs_traverse(graph, 'A')) - - def bfs_traverse(graph, start): + """ + Traversal by breadth first search. + """ visited, queue = set(), [start] while queue: node = queue.pop(0) if node not in visited: visited.add(node) - for nextNode in graph[node]: - if nextNode not in visited: - queue.append(nextNode) + for next_node in graph[node]: + if next_node not in visited: + queue.append(next_node) return visited -# print(bfs_traverse(graph, 'A')) - def dfs_traverse_recursive(graph, start, visited=None): + """ + Traversal by recursive depth first search. + """ if visited is None: visited = set() visited.add(start) - for nextNode in graph[start]: - if nextNode not in visited: - dfs_traverse_recursive(graph, nextNode, visited) + for next_node in graph[start]: + if next_node not in visited: + dfs_traverse_recursive(graph, next_node, visited) return visited - -# print(dfs_traverse_recursive(graph, 'A')) - -# def find_path(graph, start, end, visited=[]): - # # basecase - # visitied = visited + [start] - # if start == end: - # return visited - # if start not in graph: - # return None - # for node in graph[start]: - # if node not in visited: - # new_visited = find_path(graph, node, end, visited) - # return new_visited - # return None - -# print(find_path(graph, 'A', 'F')) - - diff --git a/algorithms/heap/binary_heap.py b/algorithms/heap/binary_heap.py index ac7ff63bc..776e315f6 100644 --- a/algorithms/heap/binary_heap.py +++ b/algorithms/heap/binary_heap.py @@ -1,4 +1,4 @@ -""" +r""" Binary Heap. A min heap is a complete binary tree where each node is smaller than its children. The root, therefore, is the minimum element in the tree. The min heap uses an array to represent the data and operation. For example a min heap: @@ -31,28 +31,39 @@ """ from abc import ABCMeta, abstractmethod + class AbstractHeap(metaclass=ABCMeta): """Abstract Class for Binary Heap.""" + def __init__(self): - pass + """Pass.""" + @abstractmethod def perc_up(self, i): - pass + """Pass.""" + @abstractmethod def insert(self, val): - pass + """Pass.""" + @abstractmethod - def perc_down(self,i): - pass + def perc_down(self, i): + """Pass.""" + @abstractmethod - def min_child(self,i): - pass + def min_child(self, i): + """Pass.""" + @abstractmethod def remove_min(self): - pass + """Pass.""" + + class BinaryHeap(AbstractHeap): + """Binary Heap Class""" + def __init__(self): - self.currentSize = 0 + self.current_size = 0 self.heap = [(0)] def perc_up(self, i): @@ -62,34 +73,32 @@ def perc_up(self, i): self.heap[i], self.heap[i//2] = self.heap[i//2], self.heap[i] i = i // 2 - """ + def insert(self, val): + """ Method insert always start by inserting the element at the bottom. It inserts rightmost spot so as to maintain the complete tree property. Then, it fixes the tree by swapping the new element with its parent, until it finds an appropriate spot for the element. It essentially perc_up the minimum element Complexity: O(logN) - """ - def insert(self, val): + """ self.heap.append(val) - self.currentSize = self.currentSize + 1 - self.perc_up(self.currentSize) + self.current_size = self.current_size + 1 + self.perc_up(self.current_size) - """ + """ Method min_child returns the index of smaller of 2 children of parent at index i - """ + """ + def min_child(self, i): - if 2 * i + 1 > self.currentSize: # No right child + if 2 * i + 1 > self.current_size: # No right child return 2 * i - else: - # left child > right child - if self.heap[2 * i] > self.heap[2 * i +1]: - return 2 * i + 1 - else: - return 2 * i + if self.heap[2 * i] > self.heap[2 * i + 1]: + return 2 * i + 1 + return 2 * i def perc_down(self, i): - while 2 * i < self.currentSize: + while 2 * i < self.current_size: min_child = self.min_child(i) if self.heap[min_child] < self.heap[i]: # Swap min child with parent @@ -102,10 +111,12 @@ def perc_down(self, i): min heap property is restored Complexity: O(logN) """ + def remove_min(self): ret = self.heap[1] # the smallest value at beginning - self.heap[1] = self.heap[self.currentSize] # Replace it by the last value - self.currentSize = self.currentSize - 1 + # Replace it by the last value + self.heap[1] = self.heap[self.current_size] + self.current_size = self.current_size - 1 self.heap.pop() self.perc_down(1) return ret diff --git a/algorithms/heap/k_closest_points.py b/algorithms/heap/k_closest_points.py index 8e38e05e5..6a4e03604 100644 --- a/algorithms/heap/k_closest_points.py +++ b/algorithms/heap/k_closest_points.py @@ -2,8 +2,10 @@ Idea: Maintain a max heap of k elements. We can iterate through all points. -If a point p has a smaller distance to the origin than the top element of a heap, we add point p to the heap and remove the top element. -After iterating through all points, our heap contains the k closest points to the origin. +If a point p has a smaller distance to the origin than the top element of a +heap, we add point p to the heap and remove the top element. +After iterating through all points, our heap contains the k closest points to +the origin. """ @@ -14,7 +16,8 @@ def k_closest(points, k, origin=(0, 0)): # Time: O(k+(n-k)logk) # Space: O(k) """Initialize max heap with first k points. - Python does not support a max heap; thus we can use the default min heap where the keys (distance) are negated. + Python does not support a max heap; thus we can use the default min heap + where the keys (distance) are negated. """ heap = [(-distance(p, origin), p) for p in points[:k]] heapify(heap) @@ -24,10 +27,10 @@ def k_closest(points, k, origin=(0, 0)): check if p is smaller than the root of the max heap; if it is, add p to heap and remove root. Reheapify. """ - for p in points[k:]: - d = distance(p, origin) + for point in points[k:]: + dist = distance(point, origin) - heappushpop(heap, (-d, p)) # heappushpop does conditional check + heappushpop(heap, (-dist, point)) # heappushpop does conditional check """Same as: if d < -heap[0][0]: heappush(heap, (-d,p)) @@ -37,8 +40,9 @@ def k_closest(points, k, origin=(0, 0)): Each heappushpop call takes O(logk) time. """ - return [p for nd, p in heap] # return points in heap + return [point for nd, point in heap] # return points in heap def distance(point, origin=(0, 0)): + """ Calculates the distance for a point from origo""" return (point[0] - origin[0])**2 + (point[1] - origin[1])**2 diff --git a/algorithms/heap/merge_sorted_k_lists.py b/algorithms/heap/merge_sorted_k_lists.py index 2fbfe1df2..f3600c447 100644 --- a/algorithms/heap/merge_sorted_k_lists.py +++ b/algorithms/heap/merge_sorted_k_lists.py @@ -9,28 +9,32 @@ # Definition for singly-linked list. class ListNode(object): - def __init__(self, x): - self.val = x + """ ListNode Class""" + + def __init__(self, val): + self.val = val self.next = None def merge_k_lists(lists): + """ Merge Lists """ dummy = node = ListNode(0) - h = [(n.val, n) for n in lists if n] - heapify(h) - while h: - v, n = h[0] - if n.next is None: - heappop(h) # only change heap size when necessary + list_h = [(n.val, n) for n in lists if n] + heapify(list_h) + while list_h: + _, n_val = list_h[0] + if n_val.next is None: + heappop(list_h) # only change heap size when necessary else: - heapreplace(h, (n.next.val, n.next)) - node.next = n + heapreplace(list_h, (n_val.next.val, n_val.next)) + node.next = n_val node = node.next return dummy.next def merge_k_lists(lists): + """ Merge List """ dummy = ListNode(None) curr = dummy q = PriorityQueue() diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index ab58af9a5..8a3a9e627 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -1,3 +1,6 @@ +""" +Collection of mathematical algorithms and functions. +""" from .base_conversion import * from .decimal_to_binary_ip import * from .euler_totient import * @@ -22,4 +25,3 @@ from .power import * from .magic_number import * from .krishnamurthy_number import * - diff --git a/algorithms/maths/base_conversion.py b/algorithms/maths/base_conversion.py index 5d2a2214e..6badf749e 100644 --- a/algorithms/maths/base_conversion.py +++ b/algorithms/maths/base_conversion.py @@ -1,50 +1,49 @@ """ Integer base conversion algorithm -int2base(5, 2) return '101'. -base2int('F', 16) return 15. +int_to_base(5, 2) return '101'. +base_to_int('F', 16) return 15. """ import string -def int_to_base(n, base): +def int_to_base(num, base): """ - :type n: int + :type num: int :type base: int :rtype: str """ is_negative = False - if n == 0: + if num == 0: return '0' - elif n < 0: + if num < 0: is_negative = True - n *= -1 + num *= -1 digit = string.digits + string.ascii_uppercase res = '' - while n > 0: - res += digit[n % base] - n //= base + while num > 0: + res += digit[num % base] + num //= base if is_negative: return '-' + res[::-1] - else: - return res[::-1] + return res[::-1] -def base_to_int(s, base): +def base_to_int(str_to_convert, base): """ Note : You can use int() built-in function instead of this. - :type s: str + :type str_to_convert: str :type base: int :rtype: int """ - + digit = {} - for i,c in enumerate(string.digits + string.ascii_uppercase): - digit[c] = i + for ind, char in enumerate(string.digits + string.ascii_uppercase): + digit[char] = ind multiplier = 1 res = 0 - for c in s[::-1]: - res += digit[c] * multiplier + for char in str_to_convert[::-1]: + res += digit[char] * multiplier multiplier *= base return res diff --git a/algorithms/maths/chinese_remainder_theorem.py b/algorithms/maths/chinese_remainder_theorem.py index 91d9d1d9a..256e60f16 100644 --- a/algorithms/maths/chinese_remainder_theorem.py +++ b/algorithms/maths/chinese_remainder_theorem.py @@ -1,46 +1,46 @@ -from algorithms.maths.gcd import gcd +""" +Solves system of equations using the chinese remainder theorem if possible. +""" from typing import List +from algorithms.maths.gcd import gcd -def solve_chinese_remainder(num : List[int], rem : List[int]): +def solve_chinese_remainder(nums : List[int], rems : List[int]): """ Computes the smallest x that satisfies the chinese remainder theorem for a system of equations. The system of equations has the form: - x % num[0] = rem[0] - x % num[1] = rem[1] + x % nums[0] = rems[0] + x % nums[1] = rems[1] ... - x % num[k - 1] = rem[k - 1] - Where k is the number of elements in num and rem, k > 0. - All numbers in num needs to be pariwise coprime otherwise an exception is raised + x % nums[k - 1] = rems[k - 1] + Where k is the number of elements in nums and rems, k > 0. + All numbers in nums needs to be pariwise coprime otherwise an exception is raised returns x: the smallest value for x that satisfies the system of equations """ - if not len(num) == len(rem): - raise Exception("num and rem should have equal length") - if not len(num) > 0: - raise Exception("Lists num and rem need to contain at least one element") - for n in num: - if not n > 1: - raise Exception("All numbers in num needs to be > 1") - if not _check_coprime(num): - raise Exception("All pairs of numbers in num are not coprime") - k = len(num) + if not len(nums) == len(rems): + raise Exception("nums and rems should have equal length") + if not len(nums) > 0: + raise Exception("Lists nums and rems need to contain at least one element") + for num in nums: + if not num > 1: + raise Exception("All numbers in nums needs to be > 1") + if not _check_coprime(nums): + raise Exception("All pairs of numbers in nums are not coprime") + k = len(nums) x = 1 while True: i = 0 while i < k: - if x % num[i] != rem[i]: + if x % nums[i] != rems[i]: break i += 1 if i == k: return x - else: - x += 1 + x += 1 -def _check_coprime(l : List[int]): - for i in range(len(l)): - for j in range(len(l)): - if i == j: - continue - if gcd(l[i], l[j]) != 1: +def _check_coprime(list_to_check : List[int]): + for ind, num in enumerate(list_to_check): + for num2 in list_to_check[ind + 1:]: + if gcd(num, num2) != 1: return False return True diff --git a/algorithms/maths/combination.py b/algorithms/maths/combination.py index 308b0bcc4..998536056 100644 --- a/algorithms/maths/combination.py +++ b/algorithms/maths/combination.py @@ -1,9 +1,11 @@ +""" +Functions to calculate nCr (ie how many ways to choose r items from n items) +""" def combination(n, r): """This function calculates nCr.""" if n == r or r == 0: return 1 - else: - return combination(n-1, r-1) + combination(n-1, r) + return combination(n-1, r-1) + combination(n-1, r) def combination_memo(n, r): """This function calculates nCr using memoization method.""" diff --git a/algorithms/maths/cosine_similarity.py b/algorithms/maths/cosine_similarity.py index 831e3449f..3ee7fcdd8 100644 --- a/algorithms/maths/cosine_similarity.py +++ b/algorithms/maths/cosine_similarity.py @@ -13,29 +13,30 @@ def _l2_distance(vec): Calculate l2 distance from two given vectors. """ norm = 0. - for e in vec: - norm += e * e + for element in vec: + norm += element * element norm = math.sqrt(norm) return norm -def cosine_similarity(a, b): +def cosine_similarity(vec1, vec2): """ Calculate cosine similarity between given two vectors - :type a: list - :type b: list + :type vec1: list + :type vec2: list """ - if len(a) != len(b): - raise ValueError("The two vectors must be the same length. Got shape " + str(len(a)) + " and " + str(len(b))) + if len(vec1) != len(vec2): + raise ValueError("The two vectors must be the same length. Got shape " + str(len(vec1)) + + " and " + str(len(vec2))) - norm_a = _l2_distance(a) - norm_b = _l2_distance(b) + norm_a = _l2_distance(vec1) + norm_b = _l2_distance(vec2) similarity = 0. # Calculate the dot product of two vectors - for ae, be in zip(a, b): - similarity += ae * be + for vec1_element, vec2_element in zip(vec1, vec2): + similarity += vec1_element * vec2_element similarity /= (norm_a * norm_b) diff --git a/algorithms/maths/decimal_to_binary_ip.py b/algorithms/maths/decimal_to_binary_ip.py index 579e3402a..04e65e83c 100644 --- a/algorithms/maths/decimal_to_binary_ip.py +++ b/algorithms/maths/decimal_to_binary_ip.py @@ -7,6 +7,11 @@ """ def decimal_to_binary_util(val): + """ + Convert 8-bit decimal number to binary representation + :type val: str + :rtype: str + """ bits = [128, 64, 32, 16, 8, 4, 2, 1] val = int(val) binary_rep = '' @@ -20,6 +25,9 @@ def decimal_to_binary_util(val): return binary_rep def decimal_to_binary_ip(ip): + """ + Convert dotted-decimal ip address to binary representation with help of decimal_to_binary_util + """ values = ip.split('.') binary_list = [] for val in values: diff --git a/algorithms/maths/diffie_hellman_key_exchange.py b/algorithms/maths/diffie_hellman_key_exchange.py index 91f4e8229..0d8b751fd 100644 --- a/algorithms/maths/diffie_hellman_key_exchange.py +++ b/algorithms/maths/diffie_hellman_key_exchange.py @@ -1,3 +1,6 @@ +""" +Algorithms for performing diffie-hellman key exchange. +""" import math from random import randint @@ -6,20 +9,20 @@ Code from /algorithms/maths/prime_check.py, written by 'goswami-rahul' and 'Hai Honag Dang' """ -def prime_check(n): - """Return True if n is a prime number +def prime_check(num): + """Return True if num is a prime number Else return False. """ - if n <= 1: + if num <= 1: return False - if n == 2 or n == 3: + if num == 2 or num == 3: return True - if n % 2 == 0 or n % 3 == 0: + if num % 2 == 0 or num % 3 == 0: return False j = 5 - while j * j <= n: - if n % j == 0 or n % (j + 2) == 0: + while j * j <= num: + if num % j == 0 or num % (j + 2) == 0: return False j += 6 return True @@ -29,22 +32,19 @@ def prime_check(n): For positive integer n and given integer a that satisfies gcd(a, n) = 1, the order of a modulo n is the smallest positive integer k that satisfies pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n). -Order of certain number may or may not be exist. If so, return -1. +Order of certain number may or may not exist. If not, return -1. """ def find_order(a, n): - if ((a == 1) & (n == 1)): + if (a == 1) & (n == 1): + # Exception Handeling : 1 is the order of of 1 return 1 - """ Exception Handeling : - 1 is the order of of 1 """ - else: - if (math.gcd(a, n) != 1): - print("a and n should be relative prime!") - return -1 - else: - for i in range(1, n): - if (pow(a, i) % n == 1): - return i - return -1 + if math.gcd(a, n) != 1: + print ("a and n should be relative prime!") + return -1 + for i in range(1, n): + if pow(a, i) % n == 1: + return i + return -1 """ @@ -67,7 +67,6 @@ def euler_totient(n): result -= result // n return result - """ For positive integer n and given integer a that satisfies gcd(a, n) = 1, a is the primitive root of n, if a's order k for n satisfies k = ϕ(n). @@ -76,26 +75,20 @@ def euler_totient(n): """ def find_primitive_root(n): - if (n == 1): + """ Returns all primitive roots of n. """ + if n == 1: + # Exception Handeling : 0 is the only primitive root of 1 return [0] - """ Exception Handeling : - 0 is the only primitive root of 1 """ - else: - phi = euler_totient(n) - p_root_list = [] - """ It will return every primitive roots of n. """ - for i in range(1, n): - if (math.gcd(i, n) != 1): - continue - """ To have order, a and n must be - relative prime with each other. """ - else: - order = find_order(i, n) - if (order == phi): - p_root_list.append(i) - else: - continue - return p_root_list + phi = euler_totient(n) + p_root_list = [] + for i in range (1, n): + if math.gcd(i, n) != 1: + # To have order, a and n must be relative prime with each other. + continue + order = find_order(i, n) + if order == phi: + p_root_list.append(i) + return p_root_list """ @@ -152,42 +145,40 @@ def bob_shared_key(a_pu_k, b_pr_k, p): return pow(a_pu_k, b_pr_k) % p -def diffie_hellman_key_exchange(a, p, option=None): - if (option is not None): +def diffie_hellman_key_exchange(a, p, option = None): + """ Perform diffie-helmman key exchange. """ + if option is not None: + # Print explanation of process when option parameter is given option = 1 - """ Print explanation of process - when option parameter is given """ - if (prime_check(p) is False): - print("%d is not a prime number" % p) + if prime_check(p) is False: + print(f"{p} is not a prime number") + # p must be large prime number + return False + try: + p_root_list = find_primitive_root(p) + p_root_list.index(a) + except ValueError: + print(f"{a} is not a primitive root of {p}") + # a must be primitive root of p return False - """p must be large prime number""" - else: - try: - p_root_list = find_primitive_root(p) - p_root_list.index(a) - except ValueError: - print("%d is not a primitive root of %d" % (a, p)) - return False - """ a must be primitive root of p """ - a_pr_k = alice_private_key(p) - a_pu_k = alice_public_key(a_pr_k, a, p) + a_pr_k = alice_private_key(p) + a_pu_k = alice_public_key(a_pr_k, a, p) - b_pr_k = bob_private_key(p) - b_pu_k = bob_public_key(b_pr_k, a, p) + b_pr_k = bob_private_key(p) + b_pu_k = bob_public_key(b_pr_k, a, p) - if (option == 1): - print("Private key of Alice = %d" % a_pr_k) - print("Public key of Alice = %d" % a_pu_k) - print("Private key of Bob = %d" % b_pr_k) - print("Public key of Bob = %d" % b_pu_k) + if option == 1: + print(f"Alice's private key: {a_pr_k}") + print(f"Alice's public key: {a_pu_k}") + print(f"Bob's private key: {b_pr_k}") + print(f"Bob's public key: {b_pu_k}") - """ In here, Alice send her public key to Bob, - and Bob also send his public key to Alice.""" + # In here, Alice send her public key to Bob, and Bob also send his public key to Alice. - a_sh_k = alice_shared_key(b_pu_k, a_pr_k, p) - b_sh_k = bob_shared_key(a_pu_k, b_pr_k, p) - print("Shared key calculated by Alice = %d" % a_sh_k) - print("Shared key calculated by Bob = %d" % b_sh_k) + a_sh_k = alice_shared_key(b_pu_k, a_pr_k, p) + b_sh_k = bob_shared_key(a_pu_k, b_pr_k, p) + print (f"Shared key calculated by Alice = {a_sh_k}") + print ("Shared key calculated by Bob = {b_sh_k}") - return (a_sh_k == b_sh_k) + return a_sh_k == b_sh_k diff --git a/algorithms/maths/euler_totient.py b/algorithms/maths/euler_totient.py index 047b72827..f29d382ff 100644 --- a/algorithms/maths/euler_totient.py +++ b/algorithms/maths/euler_totient.py @@ -7,12 +7,12 @@ def euler_totient(n): """Euler's totient function or Phi function. Time Complexity: O(sqrt(n)).""" - result = n; + result = n for i in range(2, int(n ** 0.5) + 1): if n % i == 0: while n % i == 0: n //= i result -= result // i if n > 1: - result -= result // n; - return result; + result -= result // n + return result diff --git a/algorithms/maths/extended_gcd.py b/algorithms/maths/extended_gcd.py index 83b657807..a0e9cbc12 100644 --- a/algorithms/maths/extended_gcd.py +++ b/algorithms/maths/extended_gcd.py @@ -1,19 +1,24 @@ -def extended_gcd(a, b): +""" +Provides extended GCD functionality for finding co-prime numbers s and t such that: +num1 * s + num2 * t = GCD(num1, num2). +Ie the coefficients of Bézout's identity. +""" +def extended_gcd(num1, num2): """Extended GCD algorithm. Return s, t, g - such that a * s + b * t = GCD(a, b) + such that num1 * s + num2 * t = GCD(num1, num2) and s and t are co-prime. """ old_s, s = 1, 0 old_t, t = 0, 1 - old_r, r = a, b - + old_r, r = num1, num2 + while r != 0: quotient = old_r / r - + old_r, r = r, old_r - quotient * r old_s, s = s, old_s - quotient * s old_t, t = t, old_t - quotient * t - + return old_s, old_t, old_r diff --git a/algorithms/maths/factorial.py b/algorithms/maths/factorial.py index 23e1f5354..f5e3ea5a2 100644 --- a/algorithms/maths/factorial.py +++ b/algorithms/maths/factorial.py @@ -1,3 +1,6 @@ +""" +Calculates the factorial with the added functionality of calculating it modulo mod. +""" def factorial(n, mod=None): """Calculates factorial iteratively. If mod is not None, then return (n! % mod) diff --git a/algorithms/maths/find_order_simple.py b/algorithms/maths/find_order_simple.py index d4866ee8c..8f69773c7 100644 --- a/algorithms/maths/find_order_simple.py +++ b/algorithms/maths/find_order_simple.py @@ -1,27 +1,27 @@ -import math - """ For positive integer n and given integer a that satisfies gcd(a, n) = 1, the order of a modulo n is the smallest positive integer k that satisfies pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n). -Order of certain number may or may not be exist. If so, return -1. +Order of a certain number may or may not be exist. If not, return -1. + +Total time complexity O(nlog(n)): +O(n) for iteration loop, +O(log(n)) for built-in power function """ + +import math + def find_order(a, n): - if ((a == 1) & (n == 1)): + """ + Find order for positive integer n and given integer a that satisfies gcd(a, n) = 1. + """ + if (a == 1) & (n == 1): + # Exception Handeling : 1 is the order of of 1 return 1 - """ Exception Handeling : - 1 is the order of of 1 """ - else: - if (math.gcd(a, n) != 1): - print ("a and n should be relative prime!") - return -1 - else: - for i in range(1, n): - if (pow(a, i) % n == 1): - return i - return -1 - -""" -Time complexity only for calculating order = O(nlog(n)) -O(n) for iteration loop, O(log(n)) for built-in power function -""" + if math.gcd(a, n) != 1: + print ("a and n should be relative prime!") + return -1 + for i in range(1, n): + if pow(a, i) % n == 1: + return i + return -1 diff --git a/algorithms/maths/find_primitive_root_simple.py b/algorithms/maths/find_primitive_root_simple.py index a5b74f6a6..366f40191 100644 --- a/algorithms/maths/find_primitive_root_simple.py +++ b/algorithms/maths/find_primitive_root_simple.py @@ -1,3 +1,6 @@ +""" +Function to find the primitive root of a number. +""" import math """ @@ -7,19 +10,20 @@ Order of certain number may or may not be exist. If so, return -1. """ def find_order(a, n): - if ((a == 1) & (n == 1)): + """ + Find order for positive integer n and given integer a that satisfies gcd(a, n) = 1. + Time complexity O(nlog(n)) + """ + if (a == 1) & (n == 1): + # Exception Handeling : 1 is the order of of 1 return 1 - """ Exception Handeling : - 1 is the order of of 1 """ - else: - if (math.gcd(a, n) != 1): - print ("a and n should be relative prime!") - return -1 - else: - for i in range(1, n): - if (pow(a, i) % n == 1): - return i - return -1 + if math.gcd(a, n) != 1: + print ("a and n should be relative prime!") + return -1 + for i in range(1, n): + if pow(a, i) % n == 1: + return i + return -1 """ Euler's totient function, also known as phi-function ϕ(n), @@ -31,41 +35,33 @@ def find_order(a, n): def euler_totient(n): """Euler's totient function or Phi function. Time Complexity: O(sqrt(n)).""" - result = n; + result = n for i in range(2, int(n ** 0.5) + 1): if n % i == 0: while n % i == 0: n //= i result -= result // i if n > 1: - result -= result // n; - return result; + result -= result // n + return result """ For positive integer n and given integer a that satisfies gcd(a, n) = 1, a is the primitive root of n, if a's order k for n satisfies k = ϕ(n). -Primitive roots of certain number may or may not be exist. +Primitive roots of certain number may or may not exist. If so, return empty list. """ - def find_primitive_root(n): - if (n == 1): + if n == 1: + # Exception Handeling : 0 is the only primitive root of 1 return [0] - """ Exception Handeling : - 0 is the only primitive root of 1 """ - else: - phi = euler_totient(n) - p_root_list = [] - """ It will return every primitive roots of n. """ - for i in range (1, n): - if (math.gcd(i, n) != 1): - continue - """ To have order, a and n must be - relative prime with each other. """ - else: - order = find_order(i, n) - if (order == phi): - p_root_list.append(i) - else: - continue - return p_root_list + phi = euler_totient(n) + p_root_list = [] + """ It will return every primitive roots of n. """ + for i in range (1, n): + #To have order, a and n must be relative prime with each other. + if math.gcd(i, n) == 1: + order = find_order(i, n) + if order == phi: + p_root_list.append(i) + return p_root_list diff --git a/algorithms/maths/gcd.py b/algorithms/maths/gcd.py index 35af7f118..189eae100 100644 --- a/algorithms/maths/gcd.py +++ b/algorithms/maths/gcd.py @@ -1,3 +1,8 @@ +""" +Functions for calculating the greatest common divisor of two integers or +their least common multiple. +""" + def gcd(a, b): """Computes the greatest common divisor of integers a and b using Euclid's Algorithm. @@ -18,12 +23,10 @@ def gcd(a, b): a, b = b, a % b return a - def lcm(a, b): """Computes the lowest common multiple of integers a and b.""" return abs(a) * abs(b) / gcd(a, b) - """ Given a positive integer x, computes the number of trailing zero of x. Example @@ -35,20 +38,19 @@ def lcm(a, b): ~~~^^^ Output : 3 """ - def trailing_zero(x): - cnt = 0 + count = 0 while x and not x & 1: - cnt += 1 + count += 1 x >>= 1 - return cnt + return count """ Given two non-negative integer a and b, computes the greatest common divisor of a and b using bitwise operator. """ - def gcd_bit(a, b): + """ Similar to gcd but uses bitwise operators and less error handling.""" tza = trailing_zero(a) tzb = trailing_zero(b) a >>= tza @@ -59,5 +61,3 @@ def gcd_bit(a, b): a -= b a >>= trailing_zero(a) return a << min(tza, tzb) - - diff --git a/algorithms/maths/generate_strobogrammtic.py b/algorithms/maths/generate_strobogrammtic.py index dd0c400c4..d051865fb 100644 --- a/algorithms/maths/generate_strobogrammtic.py +++ b/algorithms/maths/generate_strobogrammtic.py @@ -8,15 +8,14 @@ Given n = 2, return ["11","69","88","96"]. """ - def gen_strobogrammatic(n): """ + Given n, generate all strobogrammatic numbers of length n. :type n: int :rtype: List[str] """ return helper(n, n) - def helper(n, length): if n == 0: return [""] @@ -33,7 +32,6 @@ def helper(n, length): result.append("6" + middle + "9") return result - def strobogrammatic_in_range(low, high): """ :type low: str @@ -49,13 +47,11 @@ def strobogrammatic_in_range(low, high): for perm in res: if len(perm) == low_len and int(perm) < int(low): continue - elif len(perm) == high_len and int(perm) > int(high): + if len(perm) == high_len and int(perm) > int(high): continue - else: - count += 1 + count += 1 return count - def helper2(n, length): if n == 0: return [""] diff --git a/algorithms/maths/hailstone.py b/algorithms/maths/hailstone.py index 22321232b..77261ac5e 100644 --- a/algorithms/maths/hailstone.py +++ b/algorithms/maths/hailstone.py @@ -1,13 +1,21 @@ +""" +Implementation of hailstone function which generates a sequence for some n by following these rules: +* n == 1 : done +* n is even : the next n = n/2 +* n is odd : the next n = 3n + 1 +""" + def hailstone(n): - """Return the 'hailstone sequence' from n to 1 - n: The starting point of the hailstone sequence - """ + """ + Return the 'hailstone sequence' from n to 1 + n: The starting point of the hailstone sequence + """ - sequence = [n] - while n > 1: - if n%2 != 0: - n = 3*n + 1 - else: - n = int(n/2) - sequence.append(n) - return sequence \ No newline at end of file + sequence = [n] + while n > 1: + if n%2 != 0: + n = 3*n + 1 + else: + n = int(n/2) + sequence.append(n) + return sequence diff --git a/algorithms/maths/is_strobogrammatic.py b/algorithms/maths/is_strobogrammatic.py index 018e6955d..b849ddac4 100644 --- a/algorithms/maths/is_strobogrammatic.py +++ b/algorithms/maths/is_strobogrammatic.py @@ -18,8 +18,7 @@ def is_strobogrammatic(num): i = 0 j = len(num) - 1 while i <= j: - x = comb.find(num[i]+num[j]) - if x == -1: + if comb.find(num[i]+num[j]) == -1: return False i += 1 j -= 1 diff --git a/algorithms/maths/krishnamurthy_number.py b/algorithms/maths/krishnamurthy_number.py index a0a451ee4..1d41721b1 100644 --- a/algorithms/maths/krishnamurthy_number.py +++ b/algorithms/maths/krishnamurthy_number.py @@ -1,7 +1,8 @@ """ -A Krishnamurthy number is a number whose sum total of the factorials of each digit is equal to the number itself. +A Krishnamurthy number is a number whose sum total of the factorials of each digit is equal to the +number itself. -Here's what I mean by that: +The following are some examples of Krishnamurthy numbers: "145" is a Krishnamurthy Number because, 1! + 4! + 5! = 1 + 24 + 120 = 145 @@ -12,11 +13,13 @@ "357" or "25965" is NOT a Krishnamurthy Number 3! + 5! + 7! = 6 + 120 + 5040 != 357 -The following function will check if a number is a Krishnamurthy Number or not and return a boolean value. +The following function will check if a number is a Krishnamurthy Number or not and return a +boolean value. """ def find_factorial(n): + """ Calculates the factorial of a given number n """ fact = 1 while n != 0: fact *= n @@ -40,4 +43,4 @@ def krishnamurthy_number(n): temp //= 10 # returns True if number is krishnamurthy - return (sum_of_digits == n) + return sum_of_digits == n diff --git a/algorithms/maths/magic_number.py b/algorithms/maths/magic_number.py index fe62bc680..6107753d2 100644 --- a/algorithms/maths/magic_number.py +++ b/algorithms/maths/magic_number.py @@ -1,8 +1,8 @@ -"""Magic Number +""" +Magic Number A number is said to be a magic number, -if the sum of its digits are calculated till a single digit recursively -by adding the sum of the digits after every addition. -If the single digit comes out to be 1,then the number is a magic number. +if summing the digits of the number and then recursively repeating this process for the given sum +untill the number becomes a single digit number equal to 1. Example: Number = 50113 => 5+0+1+1+3=10 => 1+0=1 [This is a Magic Number] @@ -13,15 +13,14 @@ The following function checks for Magic numbers and returns a Boolean accordingly. """ - def magic_number(n): + """ Checks if n is a magic number """ total_sum = 0 # will end when n becomes 0 # AND # sum becomes single digit. while n > 0 or total_sum > 9: - # when n becomes 0 but we have a total_sum, # we update the value of n with the value of the sum digits if n == 0: @@ -32,5 +31,3 @@ def magic_number(n): # Return true if sum becomes 1 return total_sum == 1 - - diff --git a/algorithms/maths/modular_inverse.py b/algorithms/maths/modular_inverse.py index f53d0f64f..c6f849d7d 100644 --- a/algorithms/maths/modular_inverse.py +++ b/algorithms/maths/modular_inverse.py @@ -1,5 +1,5 @@ -# extended_gcd(a, b) modified from -# https://github.com/keon/algorithms/blob/master/algorithms/maths/extended_gcd.py +# extended_gcd(a, b) modified from +# https://github.com/keon/algorithms/blob/master/algorithms/maths/extended_gcd.py def extended_gcd(a: int, b: int) -> [int, int, int]: """Extended GCD algorithm. @@ -11,24 +11,24 @@ def extended_gcd(a: int, b: int) -> [int, int, int]: old_s, s = 1, 0 old_t, t = 0, 1 old_r, r = a, b - + while r != 0: quotient = old_r // r - + old_r, r = r, old_r - quotient * r old_s, s = s, old_s - quotient * s old_t, t = t, old_t - quotient * t - + return old_s, old_t, old_r def modular_inverse(a: int, m: int) -> int: """ Returns x such that a * x = 1 (mod m) - a and m must be coprime + a and m must be coprime """ - s, t, g = extended_gcd(a, m) + s, _, g = extended_gcd(a, m) if g != 1: raise ValueError("a and m must be coprime") return s % m diff --git a/algorithms/maths/next_bigger.py b/algorithms/maths/next_bigger.py index e14e22cb8..a159da197 100644 --- a/algorithms/maths/next_bigger.py +++ b/algorithms/maths/next_bigger.py @@ -1,9 +1,9 @@ """ -I just bombed an interview and made pretty much zero -progress on my interview question. +I just bombed an interview and made pretty much zero +progress on my interview question. -Given a number, find the next higher number which has the -exact same set of digits as the original number. +Given a number, find the next higher number which has the +exact same set of digits as the original number. For example: given 38276 return 38627. given 99999 return -1. (no such number exists) diff --git a/algorithms/maths/next_perfect_square.py b/algorithms/maths/next_perfect_square.py index 7e6e6b918..be2d24a24 100644 --- a/algorithms/maths/next_perfect_square.py +++ b/algorithms/maths/next_perfect_square.py @@ -1,6 +1,7 @@ """ This program will look for the next perfect square. -Check the argument to see if it is a perfect square itself, if it is not then return -1 otherwise look for the next perfect square +Check the argument to see if it is a perfect square itself, if it is not then return -1 otherwise +look for the next perfect square. for instance if you pass 121 then the script should return the next perfect square which is 144. """ @@ -9,11 +10,8 @@ def find_next_square(sq): if root.is_integer(): return (root + 1)**2 return -1 - - -# Another way: def find_next_square2(sq): - x = sq**0.5 - return -1 if x % 1 else (x+1)**2 - + """ Alternative method, works by evaluating anything non-zero as True (0.000001 --> True) """ + root = sq**0.5 + return -1 if root % 1 else (root+1)**2 diff --git a/algorithms/maths/nth_digit.py b/algorithms/maths/nth_digit.py index 381926f3e..f6454e940 100644 --- a/algorithms/maths/nth_digit.py +++ b/algorithms/maths/nth_digit.py @@ -14,4 +14,4 @@ def find_nth_digit(n): start *= 10 start += (n-1) / length s = str(start) - return int(s[(n-1) % length]) \ No newline at end of file + return int(s[(n-1) % length]) diff --git a/algorithms/maths/num_digits.py b/algorithms/maths/num_digits.py index 93f0e20f3..4ecd5c7c3 100644 --- a/algorithms/maths/num_digits.py +++ b/algorithms/maths/num_digits.py @@ -1,11 +1,12 @@ """ - num_digits() method will return the number of digits of a number in O(1) time using math.log10() method. +num_digits() method will return the number of digits of a number in O(1) time using +math.log10() method. """ import math def num_digits(n): - n=abs(n) - if(n==0): - return 1; - return int(math.log10(n))+1 + n=abs(n) + if n==0: + return 1 + return int(math.log10(n))+1 diff --git a/algorithms/maths/power.py b/algorithms/maths/power.py index 99e694faf..70d8587de 100644 --- a/algorithms/maths/power.py +++ b/algorithms/maths/power.py @@ -1,10 +1,14 @@ -def power(a: int, n: int, r: int = None): +""" +Performs exponentiation, similarly to the built-in pow() or ** functions. +Allows also for calculating the exponentiation modulo. +""" +def power(a: int, n: int, mod: int = None): """ Iterative version of binary exponentiation - + Calculate a ^ n - if r is specified, return the result modulo r - + if mod is specified, return the result modulo mod + Time Complexity : O(log(n)) Space Complexity : O(1) """ @@ -13,20 +17,20 @@ def power(a: int, n: int, r: int = None): if n & 1: ans = ans * a a = a * a - if r: - ans %= r - a %= r + if mod: + ans %= mod + a %= mod n >>= 1 return ans -def power_recur(a: int, n: int, r: int = None): +def power_recur(a: int, n: int, mod: int = None): """ Recursive version of binary exponentiation - + Calculate a ^ n - if r is specified, return the result modulo r - + if mod is specified, return the result modulo mod + Time Complexity : O(log(n)) Space Complexity : O(log(n)) """ @@ -35,11 +39,10 @@ def power_recur(a: int, n: int, r: int = None): elif n == 1: ans = a else: - ans = power_recur(a, n // 2, r) + ans = power_recur(a, n // 2, mod) ans = ans * ans if n % 2: ans = ans * a - if r: - ans %= r + if mod: + ans %= mod return ans - diff --git a/algorithms/maths/primes_sieve_of_eratosthenes.py b/algorithms/maths/primes_sieve_of_eratosthenes.py index 7c21c6d82..b0d1d96c5 100644 --- a/algorithms/maths/primes_sieve_of_eratosthenes.py +++ b/algorithms/maths/primes_sieve_of_eratosthenes.py @@ -24,7 +24,6 @@ and complexity it's also a half now. """ - def get_primes(n): """Return list of all primes less than n, Using sieve of Eratosthenes. diff --git a/algorithms/maths/pythagoras.py b/algorithms/maths/pythagoras.py index d89626039..b24b682ac 100644 --- a/algorithms/maths/pythagoras.py +++ b/algorithms/maths/pythagoras.py @@ -1,16 +1,20 @@ """ -input two of the three side in right angled triangle and return the third. use "?" to indicate the unknown side. +Given the lengths of two of the three sides of a right angled triangle, this function returns the +length of the third side. """ -def pythagoras(opposite,adjacent,hypotenuse): +def pythagoras(opposite, adjacent, hypotenuse): + """ + Returns length of a third side of a right angled triangle. + Passing "?" will indicate the unknown side. + """ try: if opposite == str("?"): return ("Opposite = " + str(((hypotenuse**2) - (adjacent**2))**0.5)) - elif adjacent == str("?"): + if adjacent == str("?"): return ("Adjacent = " + str(((hypotenuse**2) - (opposite**2))**0.5)) - elif hypotenuse == str("?"): + if hypotenuse == str("?"): return ("Hypotenuse = " + str(((opposite**2) + (adjacent**2))**0.5)) - else: - return "You already know the answer!" + return "You already know the answer!" except: - raise ValueError("invalid argument were given.") + raise ValueError("invalid argument(s) were given.") diff --git a/algorithms/maths/rabin_miller.py b/algorithms/maths/rabin_miller.py index a3aad8ef2..08b12c117 100644 --- a/algorithms/maths/rabin_miller.py +++ b/algorithms/maths/rabin_miller.py @@ -47,5 +47,5 @@ def valid_witness(a): for _ in range(k): if valid_witness(random.randrange(2, n - 2)): return False - + return True diff --git a/algorithms/maths/recursive_binomial_coefficient.py b/algorithms/maths/recursive_binomial_coefficient.py index ae57bd62d..a92420050 100644 --- a/algorithms/maths/recursive_binomial_coefficient.py +++ b/algorithms/maths/recursive_binomial_coefficient.py @@ -22,7 +22,5 @@ def recursive_binomial_coefficient(n,k): if k > n/2: #C(n,k) = C(n,n-k), so if n/2 is sufficiently small, we can reduce the problem size. return recursive_binomial_coefficient(n,n-k) - else: - #else, we know C(n,k) = (n/k)C(n-1,k-1), so we can use this to reduce our problem size. - return int((n/k)*recursive_binomial_coefficient(n-1,k-1)) - + #else, we know C(n,k) = (n/k)C(n-1,k-1), so we can use this to reduce our problem size. + return int((n/k)*recursive_binomial_coefficient(n-1,k-1)) diff --git a/algorithms/maths/rsa.py b/algorithms/maths/rsa.py index 70b7bc5cc..bbf193caa 100644 --- a/algorithms/maths/rsa.py +++ b/algorithms/maths/rsa.py @@ -21,6 +21,13 @@ (a ** b) % c == pow(a,b,c) """ +# sample usage: +# n,e,d = generate_key(16) +# data = 20 +# encrypted = pow(data,e,n) +# decrypted = pow(encrypted,d,n) +# assert decrypted == data + import random @@ -58,23 +65,23 @@ def is_prime(num): # size in bits of p and q need to add up to the size of n p_size = k / 2 q_size = k - p_size - + e = gen_prime(k, seed) # in many cases, e is also chosen to be a small constant - + while True: p = gen_prime(p_size, seed) if p % e != 1: break - + while True: q = gen_prime(q_size, seed) if q % e != 1: break - + n = p * q l = (p - 1) * (q - 1) # calculate totient function d = modinv(e, l) - + return int(n), int(e), int(d) @@ -84,13 +91,3 @@ def encrypt(data, e, n): def decrypt(data, d, n): return pow(int(data), int(d), int(n)) - - - -# sample usage: -# n,e,d = generate_key(16) -# data = 20 -# encrypted = pow(data,e,n) -# decrypted = pow(encrypted,d,n) -# assert decrypted == data - diff --git a/algorithms/maths/summing_digits.py b/algorithms/maths/summing_digits.py index f181a92eb..ec30ffda8 100644 --- a/algorithms/maths/summing_digits.py +++ b/algorithms/maths/summing_digits.py @@ -1,18 +1,19 @@ """ Recently, I encountered an interview question whose description was as below: -The number 89 is the first integer with more than one digit whose digits when raised up to consecutive powers give the same -number. For example, 89 = 8**1 + 9**2 gives the number 89. +The number 89 is the first integer with more than one digit whose digits when raised up to +consecutive powers give the same number. For example, 89 = 8**1 + 9**2 gives the number 89. The next number after 89 with this property is 135 = 1**1 + 3**2 + 5**3 = 135. -Write a function that returns a list of numbers with the above property. The function will receive range as parameter. +Write a function that returns a list of numbers with the above property. The function will +receive range as parameter. """ -def sum_dig_pow(a, b): +def sum_dig_pow(low, high): result = [] - - for number in range(a, b + 1): + + for number in range(low, high + 1): exponent = 1 # set to 1 summation = 0 # set to 1 number_as_string = str(number) diff --git a/algorithms/maths/symmetry_group_cycle_index.py b/algorithms/maths/symmetry_group_cycle_index.py index e6d01847e..01b3e05ee 100644 --- a/algorithms/maths/symmetry_group_cycle_index.py +++ b/algorithms/maths/symmetry_group_cycle_index.py @@ -1,9 +1,3 @@ -from polynomial import (Monomial, Polynomial) -from gcd import lcm -from fractions import Fraction -from typing import Dict, Union - - """ The significance of the cycle index (polynomial) of symmetry group is deeply rooted in counting the number of configurations @@ -56,16 +50,19 @@ Code: def solve(w, h, s): + s1 = get_cycle_index_sym(w) + s2 = get_cycle_index_sym(h) -s1 = get_cycle_index_sym(w) -s2 = get_cycle_index_sym(h) - -result = cycle_product_for_two_polynomials(s1, s2, s) - -return str(result) + result = cycle_product_for_two_polynomials(s1, s2, s) + return str(result) """ +from fractions import Fraction +from typing import Dict, Union +from polynomial import ( Monomial, Polynomial ) +from gcd import lcm + def cycle_product(m1: Monomial, m2: Monomial) -> Monomial: """ diff --git a/algorithms/search/__init__.py b/algorithms/search/__init__.py index 2226e4b5d..3f39479bc 100644 --- a/algorithms/search/__init__.py +++ b/algorithms/search/__init__.py @@ -1,3 +1,7 @@ +""" +Collection of search algorithms: finding the needle in a haystack. +""" + from .binary_search import * from .ternary_search import * from .first_occurrence import * diff --git a/algorithms/search/binary_search.py b/algorithms/search/binary_search.py index d8bccf06b..6b398764c 100644 --- a/algorithms/search/binary_search.py +++ b/algorithms/search/binary_search.py @@ -1,33 +1,51 @@ -# -# Binary search works for a sorted array. -# Note: The code logic is written for an array sorted in -# increasing order. -#For Binary Search, T(N) = T(N/2) + O(1) // the recurrence relation -#Apply Masters Theorem for computing Run time complexity of recurrence relations : T(N) = aT(N/b) + f(N) -#Here, a = 1, b = 2 => log (a base b) = 1 -# also, here f(N) = n^c log^k(n) //k = 0 & c = log (a base b) So, T(N) = O(N^c log^(k+1)N) = O(log(N)) +""" +Binary Search +Find an element in a sorted array (in ascending order). +""" + +# For Binary Search, T(N) = T(N/2) + O(1) // the recurrence relation +# Apply Masters Theorem for computing Run time complexity of recurrence relations: +# T(N) = aT(N/b) + f(N) +# Here, +# a = 1, b = 2 => log (a base b) = 1 +# also, here +# f(N) = n^c log^k(n) // k = 0 & c = log (a base b) +# So, +# T(N) = O(N^c log^(k+1)N) = O(log(N)) def binary_search(array, query): - lo, hi = 0, len(array) - 1 - while lo <= hi: - mid = (hi + lo) // 2 + """ + Worst-case Complexity: O(log(n)) + + reference: https://en.wikipedia.org/wiki/Binary_search_algorithm + """ + + low, high = 0, len(array) - 1 + while low <= high: + mid = (high + low) // 2 val = array[mid] if val == query: return mid - elif val < query: - lo = mid + 1 + + if val < query: + low = mid + 1 else: - hi = mid - 1 + high = mid - 1 return None def binary_search_recur(array, low, high, val): + """ + Worst-case Complexity: O(log(n)) + + reference: https://en.wikipedia.org/wiki/Binary_search_algorithm + """ + if low > high: # error case return -1 mid = (low + high) // 2 if val < array[mid]: return binary_search_recur(array, low, mid - 1, val) - elif val > array[mid]: + if val > array[mid]: return binary_search_recur(array, mid + 1, high, val) - else: - return mid + return mid diff --git a/algorithms/search/find_min_rotate.py b/algorithms/search/find_min_rotate.py index 1afc4eef2..b47fd4e87 100644 --- a/algorithms/search/find_min_rotate.py +++ b/algorithms/search/find_min_rotate.py @@ -7,6 +7,9 @@ You may assume no duplicate exists in the array. """ def find_min_rotate(array): + """ + Finds the minimum element in a sorted array that has been rotated. + """ low = 0 high = len(array) - 1 while low < high: @@ -19,10 +22,12 @@ def find_min_rotate(array): return array[low] def find_min_rotate_recur(array, low, high): + """ + Finds the minimum element in a sorted array that has been rotated. + """ mid = (low + high) // 2 if mid == low: return array[low] - elif array[mid] > array[high]: + if array[mid] > array[high]: return find_min_rotate_recur(array, mid + 1, high) - else: - return find_min_rotate_recur(array, low, mid) + return find_min_rotate_recur(array, low, mid) diff --git a/algorithms/search/first_occurrence.py b/algorithms/search/first_occurrence.py index 86dc89ced..119ba4df2 100644 --- a/algorithms/search/first_occurrence.py +++ b/algorithms/search/first_occurrence.py @@ -1,18 +1,23 @@ -# -# Find first occurance of a number in a sorted array (increasing order) -# Approach- Binary Search -# T(n)- O(log n) -# +""" +Find first occurance of a number in a sorted array (increasing order) +Approach- Binary Search +T(n)- O(log n) +""" def first_occurrence(array, query): - lo, hi = 0, len(array) - 1 - while lo <= hi: - mid = (lo + hi) // 2 + """ + Returns the index of the first occurance of the given element in an array. + The array has to be sorted in increasing order. + """ + + low, high = 0, len(array) - 1 + while low <= high: + mid = (low + high) // 2 #print("lo: ", lo, " hi: ", hi, " mid: ", mid) - if lo == hi: + if low == high: break if array[mid] < query: - lo = mid + 1 + low = mid + 1 else: - hi = mid - if array[lo] == query: - return lo + high = mid + if array[low] == query: + return low diff --git a/algorithms/search/interpolation_search.py b/algorithms/search/interpolation_search.py index 9227e1f75..5b1d00a1a 100644 --- a/algorithms/search/interpolation_search.py +++ b/algorithms/search/interpolation_search.py @@ -1,4 +1,4 @@ -""" +""" Python implementation of the Interpolation Search algorithm. Given a sorted array in increasing order, interpolation search calculates the starting point of its search according to the search key. @@ -41,14 +41,14 @@ def interpolation_search(array: List[int], search_key: int) -> int: pos = low + int(((search_key - array[low]) * (high - low) / (array[high] - array[low]))) - # search_key is found + # search_key is found if array[pos] == search_key: return pos # if search_key is larger, search_key is in upper part if array[pos] < search_key: low = pos + 1 - + # if search_key is smaller, search_key is in lower part else: high = pos - 1 diff --git a/algorithms/search/jump_search.py b/algorithms/search/jump_search.py index da8d8c32e..2ec074938 100644 --- a/algorithms/search/jump_search.py +++ b/algorithms/search/jump_search.py @@ -1,40 +1,45 @@ +""" +Jump Search + +Find an element in a sorted array. +""" + import math def jump_search(arr,target): - """Jump Search - Worst-case Complexity: O(√n) (root(n)) - All items in list must be sorted like binary search - - Find block that contains target value and search it linearly in that block - It returns a first target value in array + """ + Worst-case Complexity: O(√n) (root(n)) + All items in list must be sorted like binary search - reference: https://en.wikipedia.org/wiki/Jump_search + Find block that contains target value and search it linearly in that block + It returns a first target value in array + reference: https://en.wikipedia.org/wiki/Jump_search """ - n = len(arr) - block_size = int(math.sqrt(n)) + + length = len(arr) + block_size = int(math.sqrt(length)) block_prev = 0 block= block_size # return -1 means that array doesn't contain target value # find block that contains target value - - if arr[n - 1] < target: - return -1 - while block <= n and arr[block - 1] < target: + + if arr[length - 1] < target: + return -1 + while block <= length and arr[block - 1] < target: block_prev = block block += block_size # find target value in block - + while arr[block_prev] < target : block_prev += 1 - if block_prev == min(block, n) : + if block_prev == min(block, length) : return -1 # if there is target value in array, return it - + if arr[block_prev] == target : return block_prev - else : - return -1 + return -1 diff --git a/algorithms/search/last_occurrence.py b/algorithms/search/last_occurrence.py index 345b42395..6374625e6 100644 --- a/algorithms/search/last_occurrence.py +++ b/algorithms/search/last_occurrence.py @@ -1,16 +1,20 @@ -# -# Find last occurance of a number in a sorted array (increasing order) -# Approach- Binary Search -# T(n)- O(log n) -# +""" +Find last occurance of a number in a sorted array (increasing order) +Approach- Binary Search +T(n)- O(log n) +""" def last_occurrence(array, query): - lo, hi = 0, len(array) - 1 - while lo <= hi: - mid = (hi + lo) // 2 + """ + Returns the index of the last occurance of the given element in an array. + The array has to be sorted in increasing order. + """ + low, high = 0, len(array) - 1 + while low <= high: + mid = (high + low) // 2 if (array[mid] == query and mid == len(array)-1) or \ (array[mid] == query and array[mid+1] > query): return mid - elif (array[mid] <= query): - lo = mid + 1 + if array[mid] <= query: + low = mid + 1 else: - hi = mid - 1 + high = mid - 1 diff --git a/algorithms/search/linear_search.py b/algorithms/search/linear_search.py index cf57fcf97..d375d77f2 100644 --- a/algorithms/search/linear_search.py +++ b/algorithms/search/linear_search.py @@ -1,12 +1,15 @@ -# -# Linear search works in any array. -# -# T(n): O(n) -# +""" +Linear search works in any array. +T(n): O(n) +""" def linear_search(array, query): - for i in range(len(array)): - if array[i] == query: + """ + Find the index of the given element in the array. + There are no restrictions on the order of the elements in the array. + If the element couldn't be found, returns -1. + """ + for i, value in enumerate(array): + if value == query: return i - return -1 diff --git a/algorithms/search/next_greatest_letter.py b/algorithms/search/next_greatest_letter.py index 5abe001cd..26ec8536d 100644 --- a/algorithms/search/next_greatest_letter.py +++ b/algorithms/search/next_greatest_letter.py @@ -26,17 +26,17 @@ import bisect -""" -Using bisect libarary -""" def next_greatest_letter(letters, target): + """ + Using bisect libarary + """ index = bisect.bisect(letters, target) return letters[index % len(letters)] -""" -Using binary search: complexity O(logN) -""" def next_greatest_letter_v1(letters, target): + """ + Using binary search: complexity O(logN) + """ if letters[0] > target: return letters[0] if letters[len(letters) - 1] <= target: @@ -48,12 +48,12 @@ def next_greatest_letter_v1(letters, target): right = mid - 1 else: left = mid + 1 - return letters[left] + return letters[left] -""" -Brute force: complexity O(N) -""" def next_greatest_letter_v2(letters, target): + """ + Brute force: complexity O(N) + """ for index in letters: if index > target: return index diff --git a/algorithms/search/search_insert.py b/algorithms/search/search_insert.py index b10eb7d5f..279e64e40 100644 --- a/algorithms/search/search_insert.py +++ b/algorithms/search/search_insert.py @@ -1,14 +1,18 @@ """ -Given a sorted array and a target value, return the index if the target is -found. If not, return the index where it would be if it were inserted in order. - -For example: -[1,3,5,6], 5 -> 2 -[1,3,5,6], 2 -> 1 -[1,3,5,6], 7 -> 4 -[1,3,5,6], 0 -> 0 +Helper methods for implementing insertion sort. """ + def search_insert(array, val): + """ + Given a sorted array and a target value, return the index if the target is + found. If not, return the index where it would be if it were inserted in order. + + For example: + [1,3,5,6], 5 -> 2 + [1,3,5,6], 2 -> 1 + [1,3,5,6], 7 -> 4 + [1,3,5,6], 0 -> 0 + """ low = 0 high = len(array) - 1 while low <= high: diff --git a/algorithms/search/search_rotate.py b/algorithms/search/search_rotate.py index a92a15ee3..fe5474538 100644 --- a/algorithms/search/search_rotate.py +++ b/algorithms/search/search_rotate.py @@ -37,6 +37,10 @@ Recursion helps you understand better the above algorithm explanation """ def search_rotate(array, val): + """ + Finds the index of the given value in an array that has been sorted in + ascending order and then rotated at some unknown pivot. + """ low, high = 0, len(array) - 1 while low <= high: mid = (low + high) // 2 @@ -58,6 +62,10 @@ def search_rotate(array, val): # Recursion technique def search_rotate_recur(array, low, high, val): + """ + Finds the index of the given value in an array that has been sorted in + ascending order and then rotated at some unknown pivot. + """ if low >= high: return -1 mid = (low + high) // 2 @@ -66,10 +74,7 @@ def search_rotate_recur(array, low, high, val): if array[low] <= array[mid]: if array[low] <= val <= array[mid]: return search_rotate_recur(array, low, mid - 1, val) # Search left - else: - return search_rotate_recur(array, mid + 1, high, val) # Search right - else: - if array[mid] <= val <= array[high]: - return search_rotate_recur(array, mid + 1, high, val) # Search right - else: - return search_rotate_recur(array, low, mid - 1, val) # Search left + return search_rotate_recur(array, mid + 1, high, val) # Search right + if array[mid] <= val <= array[high]: + return search_rotate_recur(array, mid + 1, high, val) # Search right + return search_rotate_recur(array, low, mid - 1, val) # Search left diff --git a/algorithms/search/ternary_search.py b/algorithms/search/ternary_search.py index b7d36fb21..0d0ee1b66 100644 --- a/algorithms/search/ternary_search.py +++ b/algorithms/search/ternary_search.py @@ -1,37 +1,42 @@ """ -Ternary search is a divide and conquer algorithm that can be used to find an element in an array. -It is similar to binary search where we divide the array into two parts but in this algorithm, -we divide the given array into three parts and determine which has the key (searched element). +Ternary search is a divide and conquer algorithm that can be used to find an element in an array. +It is similar to binary search where we divide the array into two parts but in this algorithm, +we divide the given array into three parts and determine which has the key (searched element). We can divide the array into three parts by taking mid1 and mid2. Initially, l and r will be equal to 0 and n-1 respectively, where n is the length of the array. -mid1 = l + (r-l)/3 -mid2 = r – (r-l)/3 +mid1 = l + (r-l)/3 +mid2 = r – (r-l)/3 Note: Array needs to be sorted to perform ternary search on it. T(N) = O(log3(N)) log3 = log base 3 """ -def ternary_search(l, r, key, arr): - while r >= l: - - mid1 = l + (r-l) // 3 - mid2 = r - (r-l) // 3 +def ternary_search(left, right, key, arr): + """ + Find the given value (key) in an array sorted in ascending order. + Returns the index of the value if found, and -1 otherwise. + If the index is not in the range left..right (ie. left <= index < right) returns -1. + """ - if key == arr[mid1]: - return mid1 - if key == mid2: - return mid2 + while right >= left: + mid1 = left + (right-left) // 3 + mid2 = right - (right-left) // 3 - if key < arr[mid1]: + if key == arr[mid1]: + return mid1 + if key == mid2: + return mid2 + + if key < arr[mid1]: # key lies between l and mid1 - r = mid1 - 1 - elif key > arr[mid2]: + right = mid1 - 1 + elif key > arr[mid2]: # key lies between mid2 and r - l = mid2 + 1 - else: + left = mid2 + 1 + else: # key lies between mid1 and mid2 - l = mid1 + 1 - r = mid2 - 1 + left = mid1 + 1 + right = mid2 - 1 - # key not found - return -1 + # key not found + return -1 diff --git a/algorithms/search/two_sum.py b/algorithms/search/two_sum.py index 4251e5378..e8400fd1c 100644 --- a/algorithms/search/two_sum.py +++ b/algorithms/search/two_sum.py @@ -15,37 +15,57 @@ two_sum1: using dictionary as a hash table two_sum2: using two pointers """ -# Using binary search technique + def two_sum(numbers, target): - for i in range(len(numbers)): - second_val = target - numbers[i] + """ + Given a list of numbers sorted in ascending order, find the indices of two + numbers such that their sum is the given target. + + Using binary search. + """ + for i, number in enumerate(numbers): + second_val = target - number low, high = i+1, len(numbers)-1 while low <= high: mid = low + (high - low) // 2 if second_val == numbers[mid]: return [i + 1, mid + 1] - elif second_val > numbers[mid]: + + if second_val > numbers[mid]: low = mid + 1 else: high = mid - 1 + return None -# Using dictionary as a hash table def two_sum1(numbers, target): + """ + Given a list of numbers, find the indices of two numbers such that their + sum is the given target. + + Using a hash table. + """ dic = {} for i, num in enumerate(numbers): if target - num in dic: return [dic[target - num] + 1, i + 1] dic[num] = i + return None -# Using two pointers def two_sum2(numbers, target): - p1 = 0 # pointer 1 holds from left of array numbers - p2 = len(numbers) - 1 # pointer 2 holds from right of array numbers - while p1 < p2: - s = numbers[p1] + numbers[p2] - if s == target: - return [p1 + 1, p2 + 1] - elif s > target: - p2 = p2 - 1 + """ + Given a list of numbers sorted in ascending order, find the indices of two + numbers such that their sum is the given target. + + Using a bidirectional linear search. + """ + left = 0 # pointer 1 holds from left of array numbers + right = len(numbers) - 1 # pointer 2 holds from right of array numbers + while left < right: + current_sum = numbers[left] + numbers[right] + if current_sum == target: + return [left + 1, right + 1] + + if current_sum > target: + right = right - 1 else: - p1 = p1 + 1 + left = left + 1 diff --git a/algorithms/streaming/misra_gries.py b/algorithms/streaming/misra_gries.py index 31339094d..58fd84b5e 100644 --- a/algorithms/streaming/misra_gries.py +++ b/algorithms/streaming/misra_gries.py @@ -1,11 +1,17 @@ """ Implementation of the Misra-Gries algorithm. -Given a list of items and a value k, it returns the every item in the list that appears at least n/k times, where n is the length of the array -By default, k is set to 2, solving the majority problem. -For the majority problem, this algorithm only guarantees that if there is an element that appears more than n/2 times, it will be outputed. If there -is no such element, any arbitrary element is returned by the algorithm. Therefore, we need to iterate through again at the end. But since we have filtred -out the suspects, the memory complexity is significantly lower than it would be to create counter for every element in the list. +Given a list of items and a value k, it returns the every item in the list +that appears at least n/k times, where n is the length of the array + +By default, k is set to 2, solving the majority problem. + +For the majority problem, this algorithm only guarantees that if there is +an element that appears more than n/2 times, it will be outputed. If there +is no such element, any arbitrary element is returned by the algorithm. +Therefore, we need to iterate through again at the end. But since we have filtred +out the suspects, the memory complexity is significantly lower than +it would be to create counter for every element in the list. For example: Input misras_gries([1,4,4,4,5,4,4]) @@ -17,33 +23,38 @@ Input misras_gries([0,0,0,1,1,1] Output None """ + def misras_gries(array,k=2): - keys = {} - for i in range(len(array)): - val = str(array[i]) - if val in keys: - keys[val] = keys[val] + 1 - - elif len(keys) < k - 1: - keys[val] = 1 - - else: - for key in list(keys): - keys[key] = keys[key] - 1 - if keys[key] == 0: - del keys[key] - - suspects = keys.keys() - frequencies = {} - for suspect in suspects: - freq = _count_frequency(array,int(suspect)) - if freq >= len(array) / k: - frequencies[suspect] = freq - - return frequencies if len(frequencies) > 0 else None - + """Misra-Gries algorithm -def _count_frequency(array,element): - return array.count(element) + Keyword arguments: + array -- list of integers + k -- value of k (default 2) + """ + keys = {} + for i in array: + val = str(i) + if val in keys: + keys[val] = keys[val] + 1 + + elif len(keys) < k - 1: + keys[val] = 1 - + else: + for key in list(keys): + keys[key] = keys[key] - 1 + if keys[key] == 0: + del keys[key] + + suspects = keys.keys() + frequencies = {} + for suspect in suspects: + freq = _count_frequency(array,int(suspect)) + if freq >= len(array) / k: + frequencies[suspect] = freq + + return frequencies if len(frequencies) > 0 else None + + +def _count_frequency(array,element): + return array.count(element) diff --git a/algorithms/streaming/one_sparse_recovery.py b/algorithms/streaming/one_sparse_recovery.py index 084a9f7b8..18a26415e 100644 --- a/algorithms/streaming/one_sparse_recovery.py +++ b/algorithms/streaming/one_sparse_recovery.py @@ -1,61 +1,68 @@ -""" Non-negative 1-sparse recovery problem. This algorithm assumes we have a non negative dynamic stream. -Given a stream of tuples, where each tuple contains a number and a sign (+/-), it check if the stream is 1-sparse, meaning if the elements -in the stream cancel eacheother out in such a way that ther is only a unique number at the end. +""" +Non-negative 1-sparse recovery problem. +This algorithm assumes we have a non negative dynamic stream. + +Given a stream of tuples, where each tuple contains a number and a sign (+/-), it check if the +stream is 1-sparse, meaning if the elements in the stream cancel eacheother out in such +a way that ther is only a unique number at the end. Examples: -#1 +#1 Input: [(4,'+'), (2,'+'),(2,'-'),(4,'+'),(3,'+'),(3,'-')], -Output: 4 +Output: 4 Comment: Since 2 and 3 gets removed. -#2 +#2 Input: [(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+')] -Output: 2 +Output: 2 Comment: No other numbers present #3 Input: [(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(2,'+'),(1,'+')] -Output: None +Output: None Comment: Not 1-sparse """ def one_sparse(array): - sum_signs = 0 - bitsum = [0]*32 - sum_values = 0 - for val,sign in array: - if sign == "+": - sum_signs += 1 - sum_values += val + """1-sparse algorithm + + Keyword arguments: + array -- stream of tuples + """ + sum_signs = 0 + bitsum = [0]*32 + sum_values = 0 + for val,sign in array: + if sign == "+": + sum_signs += 1 + sum_values += val + else: + sum_signs -= 1 + sum_values -= val + + _get_bit_sum(bitsum,val,sign) + + if sum_signs > 0 and _check_every_number_in_bitsum(bitsum,sum_signs): + return int(sum_values/sum_signs) else: - sum_signs -= 1 - sum_values -= val - - _get_bit_sum(bitsum,val,sign) - - if sum_signs > 0 and _check_every_number_in_bitsum(bitsum,sum_signs): - return int(sum_values/sum_signs) - else: - return None - + return None + #Helper function to check that every entry in the list is either 0 or the same as the #sum of signs def _check_every_number_in_bitsum(bitsum,sum_signs): - for val in bitsum: - if val != 0 and val != sum_signs : - return False - return True + for val in bitsum: + if val != 0 and val != sum_signs : + return False + return True # Adds bit representation value to bitsum array def _get_bit_sum(bitsum,val,sign): - i = 0 - if sign == "+": - while(val): - bitsum[i] += val & 1 - i +=1 - val >>=1 - else : - while(val): - bitsum[i] -= val & 1 - i +=1 - val >>=1 - - + i = 0 + if sign == "+": + while val: + bitsum[i] += val & 1 + i +=1 + val >>=1 + else : + while val: + bitsum[i] -= val & 1 + i +=1 + val >>=1 diff --git a/algorithms/tree/avl/avl.py b/algorithms/tree/avl/avl.py index 102fec82d..e3cbecb7f 100644 --- a/algorithms/tree/avl/avl.py +++ b/algorithms/tree/avl/avl.py @@ -1,3 +1,4 @@ +""" Imports TreeNodes""" from tree.tree import TreeNode @@ -17,9 +18,9 @@ def insert(self, key): Insert new key into node """ # Create new node - n = TreeNode(key) + node = TreeNode(key) if not self.node: - self.node = n + self.node = node self.node.left = AvlTree() self.node.right = AvlTree() elif key < self.node.val: @@ -65,7 +66,8 @@ def update_heights(self, recursive=True): if self.node.right: self.node.right.update_heights() - self.height = 1 + max(self.node.left.height, self.node.right.height) + self.height = 1 + max(self.node.left.height, + self.node.right.height) else: self.height = -1 diff --git a/algorithms/tree/b_tree.py b/algorithms/tree/b_tree.py index bedf31b6a..1e68b432f 100644 --- a/algorithms/tree/b_tree.py +++ b/algorithms/tree/b_tree.py @@ -3,7 +3,8 @@ at least t-1 keys (t children) and at most 2*t - 1 keys (2*t children) where t is the degree of b-tree. It is not a kind of typical bst tree, because this tree grows up. -B-tree is balanced which means that the difference between height of left subtree and right subtree is at most 1. +B-tree is balanced which means that the difference between height of left +subtree and right subtree is at most 1. Complexity n - number of elements @@ -18,6 +19,8 @@ class Node: + """ Class of Node""" + def __init__(self): # self.is_leaf = is_leaf self.keys = [] @@ -28,13 +31,16 @@ def __repr__(self): @property def is_leaf(self): + """ Return if it is a leaf""" return len(self.children) == 0 class BTree: - def __init__(self, t=2): - self.min_numbers_of_keys = t - 1 - self.max_number_of_keys = 2 * t - 1 + """ Class of BTree """ + + def __init__(self, t_val=2): + self.min_numbers_of_keys = t_val - 1 + self.max_number_of_keys = 2 * t_val - 1 self.root = Node() @@ -55,7 +61,8 @@ def _split_child(self, parent: Node, child_index: int): parent.children.insert(child_index + 1, new_right_child) def insert_key(self, key): - if len(self.root.keys) >= self.max_number_of_keys: # overflow, tree increases in height + """ overflow, tree increases in height """ + if len(self.root.keys) >= self.max_number_of_keys: new_root = Node() new_root.children.append(self.root) self.root = new_root @@ -72,26 +79,27 @@ def _insert_to_nonfull_node(self, node: Node, key): if node.is_leaf: node.keys.insert(i + 1, key) else: - if len(node.children[i + 1].keys) >= self.max_number_of_keys: # overflow + # overflow + if len(node.children[i + 1].keys) >= self.max_number_of_keys: self._split_child(node, i + 1) - if node.keys[i + 1] < key: # decide which child is going to have a new key + # decide which child is going to have a new key + if node.keys[i + 1] < key: i += 1 self._insert_to_nonfull_node(node.children[i + 1], key) def find(self, key) -> bool: + """ Finds key """ current_node = self.root while True: i = len(current_node.keys) - 1 while i >= 0 and current_node.keys[i] > key: i -= 1 - if i >= 0 and current_node.keys[i] == key: return True - elif current_node.is_leaf: + if current_node.is_leaf: return False - else: - current_node = current_node.children[i + 1] + current_node = current_node.children[i + 1] def remove_key(self, key): self._remove_key(self.root, key) @@ -101,10 +109,8 @@ def _remove_key(self, node: Node, key) -> bool: key_index = node.keys.index(key) if node.is_leaf: node.keys.remove(key) - return True else: self._remove_from_nonleaf_node(node, key_index) - return True except ValueError: # key not found in node @@ -114,7 +120,8 @@ def _remove_key(self, node: Node, key) -> bool: else: i = 0 number_of_keys = len(node.keys) - while i < number_of_keys and key > node.keys[i]: # decide in which subtree may be key + # decide in which subtree may be key + while i < number_of_keys and key > node.keys[i]: i += 1 action_performed = self._repair_tree(node, i) @@ -125,15 +132,16 @@ def _remove_key(self, node: Node, key) -> bool: def _repair_tree(self, node: Node, child_index: int) -> bool: child = node.children[child_index] - if self.min_numbers_of_keys < len(child.keys) <= self.max_number_of_keys: # The leaf/node is correct + # The leaf/node is correct + if self.min_numbers_of_keys < len(child.keys) <= self.max_number_of_keys: return False if child_index > 0 and len(node.children[child_index - 1].keys) > self.min_numbers_of_keys: self._rotate_right(node, child_index) return True - if (child_index < len(node.children) - 1 and - len(node.children[child_index + 1].keys) > self.min_numbers_of_keys): # 0 <-- 1 + if (child_index < len(node.children) - 1 + and len(node.children[child_index + 1].keys) > self.min_numbers_of_keys): # 0 <-- 1 self._rotate_left(node, child_index) return True @@ -156,8 +164,10 @@ def _rotate_left(self, parent_node: Node, child_index: int): parent_node.keys[child_index] = new_parent_key if not parent_node.children[child_index + 1].is_leaf: - ownerless_child = parent_node.children[child_index + 1].children.pop(0) - # make ownerless_child as a new biggest child (with highest key) -> transfer from right subtree to left subtree + ownerless_child = parent_node.children[child_index + + 1].children.pop(0) + # make ownerless_child as a new biggest child (with highest key) + # -> transfer from right subtree to left subtree parent_node.children[child_index].children.append(ownerless_child) def _rotate_right(self, parent_node: Node, child_index: int): @@ -170,9 +180,12 @@ def _rotate_right(self, parent_node: Node, child_index: int): parent_node.keys[child_index - 1] = new_parent_key if not parent_node.children[child_index - 1].is_leaf: - ownerless_child = parent_node.children[child_index - 1].children.pop() - # make ownerless_child as a new lowest child (with lowest key) -> transfer from left subtree to right subtree - parent_node.children[child_index].children.insert(0, ownerless_child) + ownerless_child = parent_node.children[child_index + - 1].children.pop() + # make ownerless_child as a new lowest child (with lowest key) + # -> transfer from left subtree to right subtree + parent_node.children[child_index].children.insert( + 0, ownerless_child) def _merge(self, parent_node: Node, to_merge_index: int, transfered_child_index: int): from_merge_node = parent_node.children.pop(transfered_child_index) @@ -191,9 +204,11 @@ def _remove_from_nonleaf_node(self, node: Node, key_index: int): key = node.keys[key_index] left_subtree = node.children[key_index] if len(left_subtree.keys) > self.min_numbers_of_keys: - largest_key = self._find_largest_and_delete_in_left_subtree(left_subtree) + largest_key = self._find_largest_and_delete_in_left_subtree( + left_subtree) elif len(node.children[key_index + 1].keys) > self.min_numbers_of_keys: - largest_key = self._find_largest_and_delete_in_right_subtree(node.children[key_index + 1]) + largest_key = self._find_largest_and_delete_in_right_subtree( + node.children[key_index + 1]) else: self._merge(node, key_index, key_index + 1) return self._remove_key(node, key) @@ -217,7 +232,8 @@ def _find_largest_and_delete_in_right_subtree(self, node: Node): else: ch_index = 0 self._repair_tree(node, ch_index) - largest_key_in_subtree = self._find_largest_and_delete_in_right_subtree(node.children[0]) + largest_key_in_subtree = self._find_largest_and_delete_in_right_subtree( + node.children[0]) # self._repair_tree(node, ch_index) return largest_key_in_subtree diff --git a/algorithms/tree/same_tree.py b/algorithms/tree/same_tree.py index 7e87e7e08..c2805a87c 100644 --- a/algorithms/tree/same_tree.py +++ b/algorithms/tree/same_tree.py @@ -7,11 +7,11 @@ """ -def is_same_tree(p, q): - if p is None and q is None: +def is_same_tree(tree_p, tree_q): + if tree_p is None and tree_q is None: return True - if p is not None and q is not None and p.val == q.val: - return is_same_tree(p.left, q.left) and is_same_tree(p.right, q.right) + if tree_p is not None and tree_q is not None and tree_p.val == tree_q.val: + return is_same_tree(tree_p.left, tree_q.left) and is_same_tree(tree_p.right, tree_q.right) return False # Time Complexity O(min(N,M)) diff --git a/algorithms/tree/traversal/inorder.py b/algorithms/tree/traversal/inorder.py index 17cadaf95..ff1798e08 100644 --- a/algorithms/tree/traversal/inorder.py +++ b/algorithms/tree/traversal/inorder.py @@ -2,6 +2,7 @@ Time complexity : O(n) ''' + class Node: def __init__(self, val, left=None, right=None): @@ -11,6 +12,7 @@ def __init__(self, val, left=None, right=None): def inorder(root): + """ In order function """ res = [] if not root: return res @@ -24,17 +26,18 @@ def inorder(root): root = root.right return res -# Recursive Implementation def inorder_rec(root, res=None): + """ Recursive Implementation """ if root is None: return [] - if res is None: + if res is None: res = [] inorder_rec(root.left, res) res.append(root.val) inorder_rec(root.right, res) return res + if __name__ == '__main__': n1 = Node(100) n2 = Node(50) @@ -46,6 +49,6 @@ def inorder_rec(root, res=None): n1.left, n1.right = n2, n3 n2.left, n2.right = n4, n5 n3.left, n3.right = n6, n7 - - assert inorder(n1) == [25, 50, 75, 100, 125, 150, 175] + + assert inorder(n1) == [25, 50, 75, 100, 125, 150, 175] assert inorder_rec(n1) == [25, 50, 75, 100, 125, 150, 175] diff --git a/algorithms/tree/traversal/preorder.py b/algorithms/tree/traversal/preorder.py index 45346ba87..c290371b7 100644 --- a/algorithms/tree/traversal/preorder.py +++ b/algorithms/tree/traversal/preorder.py @@ -2,7 +2,9 @@ Time complexity : O(n) ''' + class Node: + """ This is a class of Node """ def __init__(self, val, left=None, right=None): self.val = val @@ -11,6 +13,7 @@ def __init__(self, val, left=None, right=None): def preorder(root): + """ Function to Preorder """ res = [] if not root: return res @@ -25,8 +28,8 @@ def preorder(root): stack.append(root.left) return res -# Recursive Implementation def preorder_rec(root, res=None): + """ Recursive Implementation """ if root is None: return [] if res is None: @@ -35,4 +38,3 @@ def preorder_rec(root, res=None): preorder_rec(root.left, res) preorder_rec(root.right, res) return res - diff --git a/algorithms/unionfind/count_islands.py b/algorithms/unionfind/count_islands.py index 56bed5bdd..ca94aa0ad 100644 --- a/algorithms/unionfind/count_islands.py +++ b/algorithms/unionfind/count_islands.py @@ -1,78 +1,126 @@ """ -A 2d grid map of m rows and n columns is initially filled with water. -We may perform an addLand operation which turns the water at position -(row, col) into a land. Given a list of positions to operate, -count the number of islands after each addLand operation. -An island is surrounded by water and is formed by connecting adjacent -lands horizontally or vertically. -You may assume all four edges of the grid are all surrounded by water. - -Given m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]]. -Initially, the 2d grid grid is filled with water. -(Assume 0 represents water and 1 represents land). - -0 0 0 -0 0 0 -0 0 0 -Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. - -1 0 0 -0 0 0 Number of islands = 1 -0 0 0 -Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. - -1 1 0 -0 0 0 Number of islands = 1 -0 0 0 -Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. - -1 1 0 -0 0 1 Number of islands = 2 -0 0 0 -Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. - -1 1 0 -0 0 1 Number of islands = 3 -0 1 0 +Defines the Union-Find (or Disjoint Set) data structure. + +A disjoint set is made up of a number of elements contained within another +number of sets. Initially, elements are put in their own set, but sets may be +merged using the `unite` operation. We can check if two elements are in the +same seet by comparing their `root`s. If they are identical, the two elements +are in the same set. All operations can be completed in O(a(n)) where `n` is +the number of elements, and `a` the inverse ackermann function. a(n) grows so +slowly that it might as well be constant for any conceivable `n`. """ +class Union: + """ + A Union-Find data structure. + + Consider the following sequence of events: + Starting with the elements 1, 2, 3, and 4: + + {1} {2} {3} {4} + + Initally they all live in their own sets, which means that `root(1) != + root(3)`, however, if we call `unite(1, 3)` we would then have the following: + + {1,3} {2} {4} + + Now we have `root(1) == root(3)`, but it is still the case that `root(1) != root(2)`. + + We may call `unite(2, 4)` and end up with: + + {1,3} {2,4} + + Again we have `root(1) != root(2)`. But after `unite(3, 4)` we end up with: + + {1,2,3,4} + + which results in `root(1) == root(2)`. + """ -class Solution(object): - def num_islands2(self, m, n, positions): - ans = [] - islands = Union() - for p in map(tuple, positions): - islands.add(p) - for dp in (0, 1), (0, -1), (1, 0), (-1, 0): - q = (p[0] + dp[0], p[1] + dp[1]) - if q in islands.id: - islands.unite(p, q) - ans += [islands.count] - return ans - -class Union(object): def __init__(self): - self.id = {} - self.sz = {} + self.parents = {} + self.size = {} self.count = 0 - def add(self, p): - self.id[p] = p - self.sz[p] = 1 + def add(self, element): + """ + Add a new set containing the single element + """ + + self.parents[element] = element + self.size[element] = 1 self.count += 1 - def root(self, i): - while i != self.id[i]: - self.id[i] = self.id[self.id[i]] - i = self.id[i] - return i + def root(self, element): + """ + Find the root element which represents the set of a given element. + That is, all elements that are in the same set will return the same + root element. + """ + + while element != self.parents[element]: + self.parents[element] = self.parents[self.parents[element]] + element = self.parents[element] + return element + + def unite(self, element1, element2): + """ + Finds the sets which contains the two elements and merges them into a + single set. + """ - def unite(self, p, q): - i, j = self.root(p), self.root(q) - if i == j: + root1, root2 = self.root(element1), self.root(element2) + if root1 == root2: return - if self.sz[i] > self.sz[j]: - i, j = j, i - self.id[i] = j - self.sz[j] += self.sz[i] + if self.size[root1] > self.size[root2]: + root1, root2 = root2, root1 + self.parents[root1] = root2 + self.size[root2] += self.size[root1] self.count -= 1 + +def num_islands(positions): + """ + Given a list of positions to operate, count the number of islands + after each addLand operation. An island is surrounded by water and is + formed by connecting adjacent lands horizontally or vertically. You may + assume all four edges of the grid are all surrounded by water. + + Given a 3x3 grid, positions = [[0,0], [0,1], [1,2], [2,1]]. + Initially, the 2d grid grid is filled with water. + (Assume 0 represents water and 1 represents land). + + 0 0 0 + 0 0 0 + 0 0 0 + Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. + + 1 0 0 + 0 0 0 Number of islands = 1 + 0 0 0 + Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. + + 1 1 0 + 0 0 0 Number of islands = 1 + 0 0 0 + Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. + + 1 1 0 + 0 0 1 Number of islands = 2 + 0 0 0 + Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. + + 1 1 0 + 0 0 1 Number of islands = 3 + 0 1 0 + """ + + ans = [] + islands = Union() + for position in map(tuple, positions): + islands.add(position) + for delta in (0, 1), (0, -1), (1, 0), (-1, 0): + adjacent = (position[0] + delta[0], position[1] + delta[1]) + if adjacent in islands.parents: + islands.unite(position, adjacent) + ans += [islands.count] + return ans diff --git a/tests/test_dp.py b/tests/test_dp.py index e8dca0bce..e92800a11 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -11,8 +11,10 @@ Job, schedule, Item, get_maximum_value, longest_increasing_subsequence, - int_divide, find_k_factor, - planting_trees + longest_increasing_subsequence_optimized, + longest_increasing_subsequence_optimized2, + int_divide,find_k_factor, + planting_trees, regex_matching ) @@ -208,6 +210,53 @@ def test_simple2(self): # assert self.assertEqual(res, 9.28538328578604) + +class TestRegexMatching(unittest.TestCase): + def test_none_0(self): + s = "" + p = "" + self.assertTrue(regex_matching.is_match(s, p)) + + def test_none_1(self): + s = "" + p = "a" + self.assertFalse(regex_matching.is_match(s, p)) + + def test_no_symbol_equal(self): + s = "abcd" + p = "abcd" + self.assertTrue(regex_matching.is_match(s, p)) + + def test_no_symbol_not_equal_0(self): + s = "abcd" + p = "efgh" + self.assertFalse(regex_matching.is_match(s, p)) + + def test_no_symbol_not_equal_1(self): + s = "ab" + p = "abb" + self.assertFalse(regex_matching.is_match(s, p)) + + def test_symbol_0(self): + s = "" + p = "a*" + self.assertTrue(regex_matching.is_match(s, p)) + + def test_symbol_1(self): + s = "a" + p = "ab*" + self.assertTrue(regex_matching.is_match(s, p)) + + def test_symbol_2(self): + # E.g. + # s a b b + # p 1 0 0 0 + # a 0 1 0 0 + # b 0 0 1 0 + # * 0 1 1 1 + s = "abb" + p = "ab*" + self.assertTrue(regex_matching.is_match(s, p)) if __name__ == '__main__': diff --git a/tests/test_graph.py b/tests/test_graph.py index 8caf858e7..eb50dd4e1 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -10,6 +10,10 @@ from algorithms.graph import bellman_ford from algorithms.graph import count_connected_number_of_component from algorithms.graph import prims_minimum_spanning +from algorithms.graph import check_digraph_strongly_connected +from algorithms.graph import cycle_detection +from algorithms.graph import find_path +from algorithms.graph import path_between_two_vertices_in_digraph import unittest @@ -278,3 +282,70 @@ def test_prim_spanning(self): 4: [[6, 1], [9, 2], [8, 3]] } self.assertEqual(19, prims_minimum_spanning(graph2)) + +class TestDigraphStronglyConnected(unittest.TestCase): + def test_digraph_strongly_connected(self): + g1 = check_digraph_strongly_connected.Graph(5) + g1.add_edge(0, 1) + g1.add_edge(1, 2) + g1.add_edge(2, 3) + g1.add_edge(3, 0) + g1.add_edge(2, 4) + g1.add_edge(4, 2) + self.assertTrue(g1.is_strongly_connected()) + + g2 = check_digraph_strongly_connected.Graph(4) + g2.add_edge(0, 1) + g2.add_edge(1, 2) + g2.add_edge(2, 3) + self.assertFalse(g2.is_strongly_connected()) + +class TestCycleDetection(unittest.TestCase): + def test_cycle_detection_with_cycle(self): + graph = {'A': ['B', 'C'], + 'B': ['D'], + 'C': ['F'], + 'D': ['E', 'F'], + 'E': ['B'], + 'F': []} + self.assertTrue(cycle_detection.contains_cycle(graph)) + + def test_cycle_detection_with_no_cycle(self): + graph = {'A': ['B', 'C'], + 'B': ['D', 'E'], + 'C': ['F'], + 'D': ['E'], + 'E': [], + 'F': []} + self.assertFalse(cycle_detection.contains_cycle(graph)) + +class TestFindPath(unittest.TestCase): + def test_find_all_paths(self): + graph = {'A': ['B', 'C'], + 'B': ['C', 'D'], + 'C': ['D', 'F'], + 'D': ['C'], + 'E': ['F'], + 'F': ['C']} + + paths = find_path.find_all_path(graph, 'A', 'F') + print(paths) + self.assertEqual(sorted(paths), sorted([ + ['A', 'C', 'F'], + ['A', 'B', 'C', 'F'], + ['A', 'B', 'D', 'C', 'F'], + ])) + +class TestPathBetweenTwoVertices(unittest.TestCase): + def test_node_is_reachable(self): + g = path_between_two_vertices_in_digraph.Graph(4) + g.add_edge(0, 1) + g.add_edge(0, 2) + g.add_edge(1, 2) + g.add_edge(2, 0) + g.add_edge(2, 3) + g.add_edge(3, 3) + + self.assertTrue(g.is_reachable(1, 3)) + self.assertFalse(g.is_reachable(3, 1)) + diff --git a/tests/test_heap.py b/tests/test_heap.py index 11e323e5f..afae0d93e 100644 --- a/tests/test_heap.py +++ b/tests/test_heap.py @@ -28,7 +28,7 @@ def test_insert(self): self.min_heap.insert(2) self.assertEqual([0, 2, 50, 4, 55, 90, 87, 7], self.min_heap.heap) - self.assertEqual(7, self.min_heap.currentSize) + self.assertEqual(7, self.min_heap.current_size) def test_remove_min(self): ret = self.min_heap.remove_min() @@ -38,7 +38,7 @@ def test_remove_min(self): self.assertEqual(4, ret) self.assertEqual([0, 7, 50, 87, 55, 90], self.min_heap.heap) - self.assertEqual(5, self.min_heap.currentSize) + self.assertEqual(5, self.min_heap.current_size) class TestSuite(unittest.TestCase): From 6440664a31822686b4fbf8282a7b34fa5d51118c Mon Sep 17 00:00:00 2001 From: abhishek singh <44000178+iabhishek15@users.noreply.github.com> Date: Tue, 8 Mar 2022 05:01:42 -0800 Subject: [PATCH 281/302] Added Kadane algorithm for max_contiguous_subsequence_sum problem with requested changes. (#861) * initial commit * initial commit! * Added Kadane's Algorithm for max_contiguous_subsequence_sum problem! * Update README.md * Update max_contiguous_subsequence_sum.py * Update max_contiguous_subsequence_sum.py * fix #854 --- README.md | 2 + algorithms/greedy/__init__.py | 1 + .../greedy/max_contiguous_subsequence_sum.py | 42 +++++++++++++++++++ tests/test_greedy.py | 21 ++++++++++ 4 files changed, 66 insertions(+) create mode 100644 algorithms/greedy/__init__.py create mode 100644 algorithms/greedy/max_contiguous_subsequence_sum.py create mode 100644 tests/test_greedy.py diff --git a/README.md b/README.md index 2234b67fa..0fce1591d 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ If you want to uninstall algorithms, it is as simple as: - [two_sum](algorithms/arrays/two_sum.py) - [move_zeros](algorithms/arrays/move_zeros.py) - [n_sum](algorithms/arrays/n_sum.py) +- [greedy](algorithms/greedy/) + - [max_contiguous_subsequence_sum](algorithms/greedy/max_contiguous_subsequence_sum.py) - [automata](algorithms/automata) - [DFA](algorithms/automata/dfa.py) - [backtrack](algorithms/backtrack) diff --git a/algorithms/greedy/__init__.py b/algorithms/greedy/__init__.py new file mode 100644 index 000000000..66184782e --- /dev/null +++ b/algorithms/greedy/__init__.py @@ -0,0 +1 @@ +from .max_contiguous_subsequence_sum import * diff --git a/algorithms/greedy/max_contiguous_subsequence_sum.py b/algorithms/greedy/max_contiguous_subsequence_sum.py new file mode 100644 index 000000000..c5eae3d6e --- /dev/null +++ b/algorithms/greedy/max_contiguous_subsequence_sum.py @@ -0,0 +1,42 @@ +''' +Algorithm used => Kadane's Algorithm + +kadane's algorithm is used for finding the maximum sum of contiguous subsequence in a sequence. +It is considered a greedy/dp algorithm but I think they more greedy than dp +here are some of the examples to understand the use case more clearly +Example1 => [-2, 3, 8, -1, 4] +result => {3, 8, -1, 4} => 14 +Example2 => [-1, 1, 0] +result => {1} => 1 +Example3 => [-1, -3, -4] +result => -1 +Example1 => [-2, 3, 8, -12, 8, 4] +result => {8, 4} => 12 +Basic Algorithm Idea + If the sum of the current contiguous subsequence after adding the value at the current position is less than the value + at the current position then we know that it will be better if we start the current contiguous subsequence from this position. + Else we add the value at the current position to the current contiguous subsequence. +Note + In the implementation, the contiguous subsequence has at least one element. + If it can have 0 elements then the result will be max(max_till_now, 0) +''' + + +def max_contiguous_subsequence_sum(arr) -> int: + arr_size = len(arr) + + if arr_size == 0: + return 0 + + max_till_now = arr[0] + curr_sub_sum = 0 + + for i in range(0, arr_size): + if curr_sub_sum + arr[i] < arr[i]: + curr_sub_sum = arr[i] + else: + curr_sub_sum += arr[i] + + max_till_now = max(max_till_now, curr_sub_sum) + + return max_till_now diff --git a/tests/test_greedy.py b/tests/test_greedy.py new file mode 100644 index 000000000..095f2a282 --- /dev/null +++ b/tests/test_greedy.py @@ -0,0 +1,21 @@ +from algorithms.greedy import ( + max_contiguous_subsequence_sum, +) + +import unittest + +class TestMaxContiguousSubsequenceSum(unittest.TestCase): + def test_max_contiguous_subsequence_sum(self): + arr1 = [-2, 3, 8, -1, 4] + arr2 = [-1, 1, 0] + arr3 = [-1, -3, -4] + arr4 = [-2, 3, 8, -12, 8, 4] + + self.assertEqual(max_contiguous_subsequence_sum(arr1), 14) + self.assertEqual(max_contiguous_subsequence_sum(arr2), 1) + self.assertEqual(max_contiguous_subsequence_sum(arr3), -1) + self.assertEqual(max_contiguous_subsequence_sum(arr4), 12) + +if __name__ == '__main__': + + unittest.main() \ No newline at end of file From 451614b6620e98ab58a83b0c7a2c79aa941ea4da Mon Sep 17 00:00:00 2001 From: Bogyeong Kim <82003678+boggy-cs@users.noreply.github.com> Date: Wed, 16 Mar 2022 18:43:09 +0900 Subject: [PATCH 282/302] added test case for test_limit (#819) --- tests/test_array.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_array.py b/tests/test_array.py index 83a4840d5..eaabfc710 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -385,6 +385,7 @@ def test_top_1(self): class TestLimit(unittest.TestCase): def test_limit(self): + self.assertListEqual(limit([1, 2, 3, 4, 5]), [1, 2, 3, 4, 5]) self.assertListEqual(limit([1, 2, 3, 4, 5], 2, 4), [2, 3, 4]) self.assertListEqual(limit([1, 2, 3, 4, 5], 2), [2, 3, 4, 5]) self.assertListEqual(limit([1, 2, 3, 4, 5], None, 4), [1, 2, 3, 4]) From 5f1a7863818b016a62ff03a45980f7ec8a970a07 Mon Sep 17 00:00:00 2001 From: Mark <38922368+mantaur@users.noreply.github.com> Date: Sun, 20 Mar 2022 12:10:40 +0100 Subject: [PATCH 283/302] Add num_perfect_squares #767 (#848) * Added num_perfect_squares * Added final test for increased coverage * Fix requested changes for issue #767. Also improved documentation and added 1 test case. * Doc update to clarify intent for issue #767 This documentation update clarifies the intent and order of each code piece. Co-authored-by: unknown Co-authored-by: ntomsic Co-authored-by: Keon --- README.md | 1 + algorithms/maths/__init__.py | 1 + algorithms/maths/num_perfect_squares.py | 47 +++++++++++++++++++++++++ tests/test_maths.py | 20 +++++++++++ 4 files changed, 69 insertions(+) create mode 100644 algorithms/maths/num_perfect_squares.py diff --git a/README.md b/README.md index 0fce1591d..0ec23733f 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,7 @@ If you want to uninstall algorithms, it is as simple as: - [next_bigger](algorithms/maths/next_bigger.py) - [next_perfect_square](algorithms/maths/next_perfect_square.py) - [nth_digit](algorithms/maths/nth_digit.py) + - [num_perfect_squares](algorithms/maths/num_perfect_squares.py) - [polynomial](algorithms/maths/polynomial.py) - [power](algorithms/maths/power.py) - [prime_check](algorithms/maths/prime_check.py) diff --git a/algorithms/maths/__init__.py b/algorithms/maths/__init__.py index 8a3a9e627..d5499b094 100644 --- a/algorithms/maths/__init__.py +++ b/algorithms/maths/__init__.py @@ -25,3 +25,4 @@ from .power import * from .magic_number import * from .krishnamurthy_number import * +from .num_perfect_squares import * diff --git a/algorithms/maths/num_perfect_squares.py b/algorithms/maths/num_perfect_squares.py new file mode 100644 index 000000000..e02eeb768 --- /dev/null +++ b/algorithms/maths/num_perfect_squares.py @@ -0,0 +1,47 @@ +""" +Given an integer num_perfect_squares will return the minimum amount of perfect squares are required +to sum to the specified number. Lagrange's four-square theorem gives us that the answer will always +be between 1 and 4 (https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem). + +Some examples: +Number | Perfect Squares representation | Answer +-------|--------------------------------|-------- +9 | 3^2 | 1 +10 | 3^2 + 1^2 | 2 +12 | 2^2 + 2^2 + 2^2 | 3 +31 | 5^2 + 2^2 + 1^2 + 1^2 | 4 +""" + +import math + +def num_perfect_squares(number): + """ + Returns the smallest number of perfect squares that sum to the specified number. + :return: int between 1 - 4 + """ + # If the number is a perfect square then we only need 1 number. + if int(math.sqrt(number))**2 == number: + return 1 + + # We check if https://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem holds and divide + # the number accordingly. Ie. if the number can be written as a sum of 3 squares (where the + # 0^2 is allowed), which is possible for all numbers except those of the form: 4^a(8b + 7). + while number > 0 and number % 4 == 0: + number /= 4 + + # If the number is of the form: 4^a(8b + 7) it can't be expressed as a sum of three (or less + # excluding the 0^2) perfect squares. If the number was of that form, the previous while loop + # divided away the 4^a, so by now it would be of the form: 8b + 7. So check if this is the case + # and return 4 since it neccessarily must be a sum of 4 perfect squares, in accordance + # with https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem. + if number % 8 == 7: + return 4 + + # By now we know that the number wasn't of the form 4^a(8b + 7) so it can be expressed as a sum + # of 3 or less perfect squares. Try first to express it as a sum of 2 perfect squares, and if + # that fails, we know finally that it can be expressed as a sum of 3 perfect squares. + for i in range(1, int(math.sqrt(number)) + 1): + if int(math.sqrt(number - i**2))**2 == number - i**2: + return 2 + + return 3 diff --git a/tests/test_maths.py b/tests/test_maths.py index ec8f65798..032145556 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -24,6 +24,7 @@ find_primitive_root, num_digits, diffie_hellman_key_exchange, krishnamurthy_number, + num_perfect_squares, chinese_remainder_theorem, ) @@ -502,6 +503,25 @@ def test_num_digits(self): self.assertEqual(3, num_digits(-254)) + +class TestNumberOfPerfectSquares(unittest.TestCase): + """[summary] + Test for the file num_perfect_squares.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_num_perfect_squares(self): + self.assertEqual(4,num_perfect_squares(31)) + self.assertEqual(3,num_perfect_squares(12)) + self.assertEqual(2,num_perfect_squares(13)) + self.assertEqual(2,num_perfect_squares(10)) + self.assertEqual(4,num_perfect_squares(1500)) + self.assertEqual(2,num_perfect_squares(1548524521)) + self.assertEqual(3,num_perfect_squares(9999999993)) + self.assertEqual(1,num_perfect_squares(9)) + + class TestChineseRemainderSolver(unittest.TestCase): def test_k_three(self): # Example which should give the answer 143 From 7d70e39c012a9fc8b0a94813786f85626b093941 Mon Sep 17 00:00:00 2001 From: code-review-doctor <72647856+code-review-doctor@users.noreply.github.com> Date: Tue, 14 Jun 2022 17:06:43 +0100 Subject: [PATCH 284/302] Fix issue probably-meant-fstring found at https://codereview.doctor (#864) --- algorithms/maths/diffie_hellman_key_exchange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/maths/diffie_hellman_key_exchange.py b/algorithms/maths/diffie_hellman_key_exchange.py index 0d8b751fd..b70b000af 100644 --- a/algorithms/maths/diffie_hellman_key_exchange.py +++ b/algorithms/maths/diffie_hellman_key_exchange.py @@ -179,6 +179,6 @@ def diffie_hellman_key_exchange(a, p, option = None): a_sh_k = alice_shared_key(b_pu_k, a_pr_k, p) b_sh_k = bob_shared_key(a_pu_k, b_pr_k, p) print (f"Shared key calculated by Alice = {a_sh_k}") - print ("Shared key calculated by Bob = {b_sh_k}") + print (f"Shared key calculated by Bob = {b_sh_k}") return a_sh_k == b_sh_k From 980d95388dab87c96ab1c774aa33d83a487db767 Mon Sep 17 00:00:00 2001 From: Brknyi <57301527+Brknyi@users.noreply.github.com> Date: Tue, 14 Jun 2022 18:10:06 +0200 Subject: [PATCH 285/302] Fix test_backtrack.py (#865) Fix invalid test related to t.sort() vs sorted(t) --- tests/test_backtrack.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_backtrack.py b/tests/test_backtrack.py index 4e9b9f612..516ed6d2d 100644 --- a/tests/test_backtrack.py +++ b/tests/test_backtrack.py @@ -184,8 +184,9 @@ def test_normal(self): ] words = ["oath", "pea", "eat", "rain"] - self.assertEqual(find_words(board, words).sort(), - ['oath', 'eat'].sort()) + result = find_words(board, words) + test_result = ['oath', 'eat'] + self.assertEqual(sorted(result),sorted(test_result)) def test_none(self): board = [ From 8aa29d7636cea5451a7a4f147a9f43a92aaa5b71 Mon Sep 17 00:00:00 2001 From: Sagnik Barman <98907729+darthdaenerys@users.noreply.github.com> Date: Wed, 6 Jul 2022 22:52:31 +0530 Subject: [PATCH 286/302] fix: removed extra blank line between sections (#870) --- algorithms/arrays/josephus.py | 1 - 1 file changed, 1 deletion(-) diff --git a/algorithms/arrays/josephus.py b/algorithms/arrays/josephus.py index 3d0ad2329..7805a388d 100644 --- a/algorithms/arrays/josephus.py +++ b/algorithms/arrays/josephus.py @@ -9,7 +9,6 @@ Output: 369485271 """ - def josephus(int_list, skip): skip = skip - 1 # list starts with 0 index idx = 0 From e63bc4d78042f5e469d966402b517214ef7ea70f Mon Sep 17 00:00:00 2001 From: Igor Izvekov Date: Wed, 27 Jul 2022 15:26:55 +0300 Subject: [PATCH 287/302] "delete_fixup" optimization (#873) * "delete_fixup" optimization * node_min.parent != node -> node_min.parent is not node --- algorithms/tree/red_black_tree/red_black_tree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/algorithms/tree/red_black_tree/red_black_tree.py b/algorithms/tree/red_black_tree/red_black_tree.py index 4b3c0d66b..20b6e7bc3 100644 --- a/algorithms/tree/red_black_tree/red_black_tree.py +++ b/algorithms/tree/red_black_tree/red_black_tree.py @@ -194,7 +194,7 @@ def delete(self, node): node_color = node_min.color temp_node = node_min.right ## - if node_min.parent != node: + if node_min.parent is not node: self.transplant(node_min, node_min.right) node_min.right = node.right node_min.right.parent = node_min @@ -208,9 +208,9 @@ def delete(self, node): def delete_fixup(self, node): # 4 cases - while node != self.root and node.color == 0: + while node is not self.root and node.color == 0: # node is not root and color is black - if node == node.parent.left: + if node is node.parent.left: # node is left node node_brother = node.parent.right From fac67d6c828398171938754e810a36653c457bc5 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Fri, 29 Jul 2022 20:37:57 +1000 Subject: [PATCH 288/302] docs: fix simple typo, occured -> occurred (#869) There is a small typo in algorithms/sort/heap_sort.py. Should read `occurred` rather than `occured`. --- algorithms/sort/heap_sort.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algorithms/sort/heap_sort.py b/algorithms/sort/heap_sort.py index ec4c7fa2b..f07d4bf61 100644 --- a/algorithms/sort/heap_sort.py +++ b/algorithms/sort/heap_sort.py @@ -38,7 +38,7 @@ def max_heapify(arr, end, simulation, iteration): if simulation: iteration = iteration + 1 print("iteration",iteration,":",*arr) - # If no swap occured, no need to keep iterating + # If no swap occurred, no need to keep iterating else: break arr[0], arr[end] = arr[end], arr[0] @@ -86,7 +86,7 @@ def min_heapify(arr, start, simulation, iteration): if simulation: iteration = iteration + 1 print("iteration",iteration,":",*arr) - # If no swap occured, no need to keep iterating + # If no swap occurred, no need to keep iterating else: break return iteration From 52b9408c98eaa8458083b27410c0c364406d6e24 Mon Sep 17 00:00:00 2001 From: Abhay Patil <72353341+patilabhay679@users.noreply.github.com> Date: Sat, 12 Nov 2022 10:24:30 +0530 Subject: [PATCH 289/302] fixed typo. (#878) --- algorithms/strings/fizzbuzz.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/strings/fizzbuzz.py b/algorithms/strings/fizzbuzz.py index 09078563b..c811afa25 100644 --- a/algorithms/strings/fizzbuzz.py +++ b/algorithms/strings/fizzbuzz.py @@ -1,5 +1,5 @@ """ -Wtite a function that returns an array containing the numbers from 1 to N, +Write a function that returns an array containing the numbers from 1 to N, where N is the parametered value. N will never be less than 1. Replace certain values however if any of the following conditions are met: From 2a129ba80efc25fca6ac58411c8df2457655cdc2 Mon Sep 17 00:00:00 2001 From: joseph-alan-jose <124856003+joseph-alan-jose@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:01:23 +0530 Subject: [PATCH 290/302] Fixed typos in two files (#898) Co-authored-by: rahulrameshan --- CONTRIBUTING.md | 2 +- algorithms/matrix/matrix_exponentiation.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ccd4eb6c..6eac6c029 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ agree to abide by the [Code of Conduct](CODE_OF_CONDUCT.md). * After that create a branch for your changes. For example: * add_XXX if you will add new algorithms or data structures. - * fix_XXX if you will fixe a bug on a certain algorithm or data structure. + * fix_XXX if you will fix a bug on a certain algorithm or data structure. * test_XXX if you wrote a test/s. * doc_XXX if you added to or edited documentation. diff --git a/algorithms/matrix/matrix_exponentiation.py b/algorithms/matrix/matrix_exponentiation.py index 2c836fe07..d9b45ba21 100644 --- a/algorithms/matrix/matrix_exponentiation.py +++ b/algorithms/matrix/matrix_exponentiation.py @@ -1,6 +1,6 @@ def multiply(matA: list, matB: list) -> list: """ - Multiplies two square matrices matA and matB od size n x n + Multiplies two square matrices matA and matB of size n x n Time Complexity: O(n^3) """ n = len(matA) From fd86fd1e8a1ca585562382db59603ece58a31112 Mon Sep 17 00:00:00 2001 From: Abhay Patil <72353341+patilabhay679@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:02:16 +0530 Subject: [PATCH 291/302] modified the return from both main and helper. (#886) It looks like there is no need to create a copy, we can replace the new elements inplace. --- algorithms/sort/merge_sort.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/algorithms/sort/merge_sort.py b/algorithms/sort/merge_sort.py index 351a4c5e8..e2d7f05b9 100644 --- a/algorithms/sort/merge_sort.py +++ b/algorithms/sort/merge_sort.py @@ -10,7 +10,9 @@ def merge_sort(arr): left, right = merge_sort(arr[:mid]), merge_sort(arr[mid:]) # Merge each side together - return merge(left, right, arr.copy()) + # return merge(left, right, arr.copy()) # changed, no need to copy, mutate inplace. + merge(left,right,arr) + return arr def merge(left, right, merged): @@ -35,4 +37,4 @@ def merge(left, right, merged): merged[left_cursor + right_cursor] = right[right_cursor] # Return result - return merged + # return merged # do not return anything, as it is replacing inplace. From e24247fb1455bc2d1ddfcd5d8923f9a35cd2a27a Mon Sep 17 00:00:00 2001 From: Mohan Date: Wed, 8 Mar 2023 15:02:38 +0530 Subject: [PATCH 292/302] Fix search_range and add test (#868) --- algorithms/search/search_range.py | 14 +++++++------- tests/test_search.py | 5 +++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/algorithms/search/search_range.py b/algorithms/search/search_range.py index 116d8f541..f0f2bfba0 100644 --- a/algorithms/search/search_range.py +++ b/algorithms/search/search_range.py @@ -17,17 +17,17 @@ def search_range(nums, target): """ low = 0 high = len(nums) - 1 - while low <= high: + # breaks at low == high + # both pointing to first occurence of target + while low < high: mid = low + (high - low) // 2 - if target < nums[mid]: - high = mid - 1 - elif target > nums[mid]: - low = mid + 1 + if target <= nums[mid]: + high = mid else: - break + low = mid + 1 for j in range(len(nums) - 1, -1, -1): if nums[j] == target: - return [mid, j] + return [low, j] return [-1, -1] diff --git a/tests/test_search.py b/tests/test_search.py index 8f9555048..f515cfcb9 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -91,6 +91,11 @@ def test_search_range(self): self.assertEqual([1, 2], search_range(array, 7)) self.assertEqual([-1, -1], search_range(array, 11)) + array = [5, 7, 7, 7, 7, 8, 8, 8, 8, 10] + self.assertEqual([5, 8], search_range(array, 8)) + self.assertEqual([1, 4], search_range(array, 7)) + self.assertEqual([-1, -1], search_range(array, 11)) + def test_find_min_rotate(self): array = [4, 5, 6, 7, 0, 1, 2] self.assertEqual(0, find_min_rotate(array)) From 51f93c600bd2e20c33c46b014819bb1c5c0e429c Mon Sep 17 00:00:00 2001 From: ekorre1001 <78041058+ekorre1001@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:33:02 +0100 Subject: [PATCH 293/302] add FFT and tests (#847) --- algorithms/maths/fft.py | 32 ++++++++++++++++++++++++++++++++ tests/test_maths.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 algorithms/maths/fft.py diff --git a/algorithms/maths/fft.py b/algorithms/maths/fft.py new file mode 100644 index 000000000..6f6697421 --- /dev/null +++ b/algorithms/maths/fft.py @@ -0,0 +1,32 @@ +""" +Implementation of the Cooley-Tukey, which is the most common FFT algorithm. + +Input: an array of complex values which has a size of N, where N is an integer power of 2 +Output: an array of complex values which is the discrete fourier transform of the input + +Example 1 +Input: [2.0+2j, 1.0+3j, 3.0+1j, 2.0+2j] +Output: [8+8j, 2j, 2-2j, -2+0j] + + +Pseudocode: https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm +""" +from cmath import exp, pi + +def fft(x): + """ Recursive implementation of the Cooley-Tukey""" + N = len(x) + if N == 1: + return x + + # get the elements at even/odd indices + even = fft(x[0::2]) + odd = fft(x[1::2]) + + y = [0 for i in range(N)] + for k in range(N//2): + q = exp(-2j*pi*k/N)*odd[k] + y[k] = even[k] + q + y[k + N//2] = even[k] - q + + return y diff --git a/tests/test_maths.py b/tests/test_maths.py index 032145556..c4a54af03 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -26,6 +26,7 @@ diffie_hellman_key_exchange, krishnamurthy_number, num_perfect_squares, chinese_remainder_theorem, + fft ) import unittest @@ -556,5 +557,41 @@ def test_empty_lists(self): chinese_remainder_theorem.solve_chinese_remainder(num, rem) +class TestFFT(unittest.TestCase): + """[summary] + Test for the file fft.py + + Arguments: + unittest {[type]} -- [description] + """ + def test_real_numbers(self): + x = [1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0] + y = [4.000, 2.613, 0.000, 1.082, 0.000, 1.082, 0.000, 2.613] + # abs(complex) returns the magnitude + result = [float("%.3f" % abs(f)) for f in fft.fft(x)] + self.assertEqual(result, y) + + def test_all_zero(self): + x = [0.0, 0.0, 0.0, 0.0] + y = [0.0, 0.0, 0.0, 0.0] + result = [float("%.1f" % abs(f)) for f in fft.fft(x)] + self.assertEqual(result, y) + + def test_all_ones(self): + x = [1.0, 1.0, 1.0, 1.0] + y = [4.0, 0.0, 0.0, 0.0] + result = [float("%.1f" % abs(f)) for f in fft.fft(x)] + self.assertEqual(result, y) + + def test_complex_numbers(self): + x = [2.0+2j, 1.0+3j, 3.0+1j, 2.0+2j] + real = [8.0, 0.0, 2.0, -2.0] + imag = [8.0, 2.0, -2.0, 0.0] + realResult = [float("%.1f" % f.real) for f in fft.fft(x)] + imagResult = [float("%.1f" % f.imag) for f in fft.fft(x)] + self.assertEqual(real, realResult) + self.assertEqual(imag, imagResult) + + if __name__ == "__main__": unittest.main() From c0e5404a3303a4def1816f336af10eb56fd6a19c Mon Sep 17 00:00:00 2001 From: psalqvist <63300368+psalqvist@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:35:29 +0100 Subject: [PATCH 294/302] feat: add dynamic programming algorithm to strings.min_distance.py (#838) also added a small unit test to ensure the algorithm is correct fixes: #15 Co-authored-by: Philip Salqvist --- algorithms/strings/min_distance.py | 46 ++++++++++++++++++++++++++---- tests/test_strings.py | 8 ++++++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/algorithms/strings/min_distance.py b/algorithms/strings/min_distance.py index 4e80f471f..b63f5db2a 100644 --- a/algorithms/strings/min_distance.py +++ b/algorithms/strings/min_distance.py @@ -12,17 +12,51 @@ """ def min_distance(word1, word2): + """ + Finds minimum distance by getting longest common subsequence + + :type word1: str + :type word2: str + :rtype: int + """ return len(word1) + len(word2) - 2 * lcs(word1, word2, len(word1), len(word2)) -def lcs(s1, s2, i, j): +def lcs(word1, word2, i, j): """ - The length of longest common subsequence among the two given strings s1 and s2 + The length of longest common subsequence among the two given strings word1 and word2 """ if i == 0 or j == 0: return 0 - elif s1[i - 1] == s2[j - 1]: - return 1 + lcs(s1, s2, i - 1, j - 1) + if word1[i - 1] == word2[j - 1]: + return 1 + lcs(word1, word2, i - 1, j - 1) + return max(lcs(word1, word2, i - 1, j), lcs(word1, word2, i, j - 1)) + +def min_distance_dp(word1, word2): + """ + Finds minimum distance in a dynamic programming manner + TC: O(length1*length2), SC: O(length1*length2) + + :type word1: str + :type word2: str + :rtype: int + """ + length1, length2 = len(word1)+1, len(word2)+1 + res = [[0 for _ in range(length2)] for _ in range(length1)] + + if length1 == length2: + for i in range(1, length1): + res[i][0], res[0][i] = i, i else: - return max(lcs(s1, s2, i - 1, j), lcs(s1, s2, i, j - 1)) + for i in range(length1): + res[i][0] = i + for i in range(length2): + res[0][i] = i + + for i in range(1, length1): + for j in range(1, length2): + if word1[i-1] == word2[j-1]: + res[i][j] = res[i-1][j-1] + else: + res[i][j] = min(res[i-1][j], res[i][j-1]) + 1 -# TODO: Using dynamic programming + return res[len(word1)][len(word2)] diff --git a/tests/test_strings.py b/tests/test_strings.py index 57f5ff0c1..e7a68302a 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -32,6 +32,7 @@ repeat_string, text_justification, min_distance, + min_distance_dp, longest_common_prefix_v1, longest_common_prefix_v2, longest_common_prefix_v3, rotate, rotate_alt, @@ -535,6 +536,13 @@ class TestMinDistance(unittest.TestCase): def test_min_distance(self): self.assertEqual(2, min_distance("sea", "eat")) self.assertEqual(6, min_distance("abAlgocrithmf", "Algorithmmd")) + self.assertEqual(4, min_distance("acbbd", "aabcd")) + +class TestMinDistanceDP(unittest.TestCase): + def test_min_distance(self): + self.assertEqual(2, min_distance_dp("sea", "eat")) + self.assertEqual(6, min_distance_dp("abAlgocrithmf", "Algorithmmd")) + self.assertEqual(4, min_distance("acbbd", "aabcd")) class TestLongestCommonPrefix(unittest.TestCase): From a336ee8f6595ad0ef14de6acbae765b36af7c5ba Mon Sep 17 00:00:00 2001 From: Anujeet Kunturkar <89986435+Anujeet23@users.noreply.github.com> Date: Tue, 4 Apr 2023 18:48:36 +0530 Subject: [PATCH 295/302] Update binary_search.py (#902) * Update binary_search.py * Update first_occurrence.py --- algorithms/search/binary_search.py | 13 +++++++------ algorithms/search/first_occurrence.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/algorithms/search/binary_search.py b/algorithms/search/binary_search.py index 6b398764c..2a7c9bc3e 100644 --- a/algorithms/search/binary_search.py +++ b/algorithms/search/binary_search.py @@ -34,18 +34,19 @@ def binary_search(array, query): high = mid - 1 return None +#In this below function we are passing array, it's first index , last index and value to be searched def binary_search_recur(array, low, high, val): """ Worst-case Complexity: O(log(n)) reference: https://en.wikipedia.org/wiki/Binary_search_algorithm """ - - if low > high: # error case +#Here in Logic section first we are checking if low is greater than high which means its an error condition because low index should not move ahead of high index + if low > high: return -1 - mid = (low + high) // 2 - if val < array[mid]: - return binary_search_recur(array, low, mid - 1, val) + mid = low + (high-low)//2 #This mid will not break integer range + if val < array[mid]: + return binary_search_recur(array, low, mid - 1, val) #Go search in the left subarray if val > array[mid]: - return binary_search_recur(array, mid + 1, high, val) + return binary_search_recur(array, mid + 1, high, val) #Go search in the right subarray return mid diff --git a/algorithms/search/first_occurrence.py b/algorithms/search/first_occurrence.py index 119ba4df2..9d9beaae1 100644 --- a/algorithms/search/first_occurrence.py +++ b/algorithms/search/first_occurrence.py @@ -11,7 +11,7 @@ def first_occurrence(array, query): low, high = 0, len(array) - 1 while low <= high: - mid = (low + high) // 2 + mid = low + (high-low)//2 #Now mid will be ininteger range #print("lo: ", lo, " hi: ", hi, " mid: ", mid) if low == high: break From 1117ffe74b6c1232e3e048e6048819985c19be85 Mon Sep 17 00:00:00 2001 From: PIYUSH GOSWAMI Date: Tue, 6 Feb 2024 04:31:28 +0530 Subject: [PATCH 296/302] Optimize longest_non_repeat.py (#914) Added window sliding approach to find longest non repeating sub string --- algorithms/arrays/longest_non_repeat.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/algorithms/arrays/longest_non_repeat.py b/algorithms/arrays/longest_non_repeat.py index 786c03dfe..b25a952ca 100644 --- a/algorithms/arrays/longest_non_repeat.py +++ b/algorithms/arrays/longest_non_repeat.py @@ -88,4 +88,22 @@ def get_longest_non_repeat_v2(string): max_len = index - start + 1 sub_string = string[start: index + 1] used_char[char] = index - return max_len, sub_string \ No newline at end of file + return max_len, sub_string + +def get_longest_non_repeat_v3(string): + """ + Find the length of the longest substring + without repeating characters. + Uses window sliding approach. + Return max_len and the substring as a tuple + """ + longest_substring = '' + seen = set() + start_idx = 0 + for i in range(len(string)): + while string[i] in seen: + seen.remove(string[start_idx]) + start_idx += 1 + seen.add(string[i]) + longest_substring = max(longest_substring, string[start_idx: i+1], key=len) + return len(longest_substring), longest_substring From 40c944c0457168749f66095e9b7e86f85c3fa709 Mon Sep 17 00:00:00 2001 From: zlhanq <127005873+zlhanq@users.noreply.github.com> Date: Tue, 6 Feb 2024 07:01:59 +0800 Subject: [PATCH 297/302] Update summarize_ranges.py (#912) --- algorithms/arrays/summarize_ranges.py | 28 +++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/algorithms/arrays/summarize_ranges.py b/algorithms/arrays/summarize_ranges.py index 8cfba68e1..58de7421a 100644 --- a/algorithms/arrays/summarize_ranges.py +++ b/algorithms/arrays/summarize_ranges.py @@ -6,22 +6,20 @@ """ -def summarize_ranges(array): - """ - :type array: List[int] - :rtype: List[] - """ +from typing import List + +def summarize_ranges(array: List[int]) -> List[str]: res = [] if len(array) == 1: return [str(array[0])] - i = 0 - while i < len(array): - num = array[i] - while i + 1 < len(array) and array[i + 1] - array[i] == 1: - i += 1 - if array[i] != num: - res.append((num, array[i])) + it = iter(array) + start = end = next(it) + for num in it: + if num - end == 1: + end = num else: - res.append((num, num)) - i += 1 - return res + res.append((start, end) if start != end else (start,)) + start = end = num + res.append((start, end) if start != end else (start,)) + return [f"{r[0]}-{r[1]}" if len(r) > 1 else str(r[0]) for r in res] + From e9c28af6d0384f91c96c293ec3a1d05b6f61b0ea Mon Sep 17 00:00:00 2001 From: Rubal Singh Date: Tue, 6 Feb 2024 04:32:18 +0530 Subject: [PATCH 298/302] Add Kosaraju algorithm (#910) * added kosaraju's algorithm under /algorithms/graph * added test case for /algorithms/graph/strongly_connected_component_kosaraju --------- Co-authored-by: Rubal Singh --- .../strongly_connected_components_kosaraju.py | 81 +++++++++++++++++++ tests/test_graph.py | 17 ++++ 2 files changed, 98 insertions(+) create mode 100644 algorithms/graph/strongly_connected_components_kosaraju.py diff --git a/algorithms/graph/strongly_connected_components_kosaraju.py b/algorithms/graph/strongly_connected_components_kosaraju.py new file mode 100644 index 000000000..0c82a7af6 --- /dev/null +++ b/algorithms/graph/strongly_connected_components_kosaraju.py @@ -0,0 +1,81 @@ +""" +Implementing strongly connected components in a graph using Kosaraju's algorithm. +https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm +""" + + +class Kosaraju: + """ + Kosaraju's algorithm use depth first search approach to find strongly connected components in a directed graph. + Approach: + 1. Make a DFS call to keep track of finish time of each vertex. + 2. Tranpose the original graph. ie 1->2 transpose is 1<-2 + 3. Make another DFS call to calculate strongly connected components. + """ + + def dfs(self, i, V, adj, visited, stk): + visited[i] = 1 + + for x in adj[i]: + if visited[x] == -1: + self.dfs(x, V, adj, visited, stk) + + stk.append(i) + + def kosaraju(self, V, adj): + + stk, visited = [], [-1]*(V+1) + + for i in range(V): + if visited[i] == -1: + self.dfs(i, V, adj, visited, stk) + + stk.reverse() + res = stk.copy() + + ans, visited1 = 0, [-1]*(V+1) + + adj1 = [[] for x in range(V)] + + for i in range(len(adj)): + for x in adj[i]: + adj1[x].append(i) + + for i in range(len(res)): + if visited1[res[i]] == -1: + ans += 1 + self.dfs(res[i], V, adj1, visited1, stk) + + return ans + + +def main(): + """ + Let's look at the sample input. + + 6 7 #no of vertex, no of edges + 0 2 #directed edge 0->2 + 1 0 + 2 3 + 3 1 + 3 4 + 4 5 + 5 4 + + calculating no of strongly connected compnenets in a directed graph. + answer should be: 2 + 1st strong component: 0->2->3->1->0 + 2nd strongly connected component: 4->5->4 + """ + V, E = map(int, input().split()) + adj = [[] for x in range(V)] + + for i in range(E): + u, v = map(int, input().split()) + adj[u].append(v) + + print(Kosaraju().kosaraju(V, adj)) + + +if __name__ == '__main__': + main() diff --git a/tests/test_graph.py b/tests/test_graph.py index eb50dd4e1..540d29983 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -14,6 +14,7 @@ from algorithms.graph import cycle_detection from algorithms.graph import find_path from algorithms.graph import path_between_two_vertices_in_digraph +from algorithms.graph import strongly_connected_components_kosaraju import unittest @@ -349,3 +350,19 @@ def test_node_is_reachable(self): self.assertTrue(g.is_reachable(1, 3)) self.assertFalse(g.is_reachable(3, 1)) +class TestStronglyConnectedComponentsKosaraju(unittest.TestCase): + def test_kosaraju_algorithm(self): + V = 6 + adj = [ + [2], + [0], + [3], + [1, 4], + [5], + [4] + ] + + result = strongly_connected_components_kosaraju.Kosaraju().kosaraju(V, adj) + + # Expected result: 2 strongly connected components + self.assertEqual(result, 2) From cad4754bc71742c2d6fcbd3b92ae74834d359844 Mon Sep 17 00:00:00 2001 From: oDqnger <103481200+oDqnger@users.noreply.github.com> Date: Mon, 5 Feb 2024 23:03:25 +0000 Subject: [PATCH 299/302] Add remove duplicates (#905) * Initial commit for remove duplicates * Made changes to readme and added test case --- README.md | 1 + algorithms/arrays/__init__.py | 1 + algorithms/arrays/remove_duplicates.py | 18 ++++++++++++++++++ tests/test_array.py | 10 ++++++++++ 4 files changed, 30 insertions(+) create mode 100644 algorithms/arrays/remove_duplicates.py diff --git a/README.md b/README.md index 0ec23733f..65caeb5ca 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ If you want to uninstall algorithms, it is as simple as: - [merge_intervals](algorithms/arrays/merge_intervals.py) - [missing_ranges](algorithms/arrays/missing_ranges.py) - [plus_one](algorithms/arrays/plus_one.py) + - [remove_duplicates](algorithms/arrays/remove_duplicates.py) - [rotate](algorithms/arrays/rotate.py) - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - [three_sum](algorithms/arrays/three_sum.py) diff --git a/algorithms/arrays/__init__.py b/algorithms/arrays/__init__.py index 9670db750..2632ca1c7 100644 --- a/algorithms/arrays/__init__.py +++ b/algorithms/arrays/__init__.py @@ -16,3 +16,4 @@ from .two_sum import * from .limit import * from .n_sum import * +from .remove_duplicates import * \ No newline at end of file diff --git a/algorithms/arrays/remove_duplicates.py b/algorithms/arrays/remove_duplicates.py new file mode 100644 index 000000000..1c0bc0a06 --- /dev/null +++ b/algorithms/arrays/remove_duplicates.py @@ -0,0 +1,18 @@ +""" +This algorithm removes any duplicates from an array and returns a new array with those duplicates +removed. + +For example: + +Input: [1, 1 ,1 ,2 ,2 ,3 ,4 ,4 ,"hey", "hey", "hello", True, True] +Output: [1, 2, 3, 4, 'hey', 'hello'] +""" + +def remove_duplicates(array): + new_array = [] + + for item in array: + if item not in new_array: + new_array.append(item) + + return new_array \ No newline at end of file diff --git a/tests/test_array.py b/tests/test_array.py index eaabfc710..f1ad11693 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -9,6 +9,7 @@ missing_ranges, move_zeros, plus_one_v1, plus_one_v2, plus_one_v3, + remove_duplicates rotate_v1, rotate_v2, rotate_v3, summarize_ranges, three_sum, @@ -298,6 +299,15 @@ def test_plus_one_v3(self): self.assertListEqual(plus_one_v3([9, 9, 9, 9]), [1, 0, 0, 0, 0]) +class TestRemoveDuplicate(unittest.TestCase): + + def test_remove_duplicates(self): + self.assertListEqual(remove_duplicates([1,1,1,2,2,2,3,3,4,4,5,6,7,7,7,8,8,9,10,10])) + self.assertListEqual(remove_duplicates(["hey", "hello", "hello", "car", "house", "house"])) + self.assertListEqual(remove_duplicates([True, True, False, True, False, None, None])) + self.assertListEqual(remove_duplicates([1,1,"hello", "hello", True, False, False])) + self.assertListEqual(remove_duplicates([1, "hello", True, False])) + class TestRotateArray(unittest.TestCase): From 66eb36d27721676000f9a656a2fa3987963de176 Mon Sep 17 00:00:00 2001 From: Canderton74 <108482522+Canderton74@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:29:58 -0400 Subject: [PATCH 300/302] Fixed polynomial division (#2130) --- algorithms/maths/polynomial.py | 79 ++++++++++++++++++++++++++-------- tests/test_polynomial.py | 70 ++++++++++++++++++++---------- 2 files changed, 109 insertions(+), 40 deletions(-) diff --git a/algorithms/maths/polynomial.py b/algorithms/maths/polynomial.py index 07a0c3b8a..81faf2b7e 100644 --- a/algorithms/maths/polynomial.py +++ b/algorithms/maths/polynomial.py @@ -438,10 +438,7 @@ def __floordiv__(self, other: Union[int, float, Fraction, Monomial]): # def __truediv__(self, other: Union[int, float, Fraction, Monomial, Polynomial]) -> Polynomial: def __truediv__(self, other: Union[int, float, Fraction, Monomial]): """ - For Polynomials, only division by a monomial - is defined. - - TODO: Implement polynomial / polynomial. + For Polynomial division, no remainder is provided. Must use poly_long_division() to capture remainder """ if isinstance(other, int) or isinstance(other, float) or isinstance(other, Fraction): return self.__truediv__( Monomial({}, other) ) @@ -449,17 +446,11 @@ def __truediv__(self, other: Union[int, float, Fraction, Monomial]): poly_temp = reduce(lambda acc, val: acc + val, map(lambda x: x / other, [z for z in self.all_monomials()]), Polynomial([Monomial({}, 0)])) return poly_temp elif isinstance(other, Polynomial): - if Monomial({}, 0) in other.all_monomials(): - if len(other.all_monomials()) == 2: - temp_set = {x for x in other.all_monomials() if x != Monomial({}, 0)} - only = temp_set.pop() - return self.__truediv__(only) - elif len(other.all_monomials()) == 1: - temp_set = {x for x in other.all_monomials()} - only = temp_set.pop() - return self.__truediv__(only) - - raise ValueError('Can only divide a polynomial by an int, float, Fraction, or a Monomial.') + # Call long division + quotient, remainder = self.poly_long_division(other) + return quotient # Return just the quotient, remainder is ignored here + + raise ValueError('Can only divide a polynomial by an int, float, Fraction, Monomial, or Polynomial.') return @@ -526,7 +517,59 @@ def subs(self, substitutions: Union[int, float, Fraction, Dict[int, Union[int, f def __str__(self) -> str: """ - Get a string representation of - the polynomial. + Get a properly formatted string representation of the polynomial. + """ + sorted_monos = sorted(self.all_monomials(), key=lambda m: sorted(m.variables.items(), reverse=True), + reverse=True) + return ' + '.join(str(m) for m in sorted_monos if m.coeff != Fraction(0, 1)) + + def poly_long_division(self, other: 'Polynomial') -> tuple['Polynomial', 'Polynomial']: """ - return ' + '.join(str(m) for m in self.all_monomials() if m.coeff != Fraction(0, 1)) + Perform polynomial long division + Returns (quotient, remainder) + """ + if not isinstance(other, Polynomial): + raise ValueError("Can only divide by another Polynomial.") + + if len(other.all_monomials()) == 0: + raise ValueError("Cannot divide by zero polynomial.") + + quotient = Polynomial([]) + remainder = self.clone() + + divisor_monos = sorted(other.all_monomials(), key=lambda m: sorted(m.variables.items(), reverse=True), + reverse=True) + divisor_lead = divisor_monos[0] + + while remainder.all_monomials() and max(remainder.variables(), default=-1) >= max(other.variables(), + default=-1): + remainder_monos = sorted(remainder.all_monomials(), key=lambda m: sorted(m.variables.items(), reverse=True), + reverse=True) + remainder_lead = remainder_monos[0] + + if not all(remainder_lead.variables.get(var, 0) >= divisor_lead.variables.get(var, 0) for var in + divisor_lead.variables): + break + + lead_quotient = remainder_lead / divisor_lead + quotient = quotient + Polynomial([lead_quotient]) # Convert Monomial to Polynomial + + remainder = remainder - ( + Polynomial([lead_quotient]) * other) # Convert Monomial to Polynomial before multiplication + + return quotient, remainder + +dividend = Polynomial([ + Monomial({1: 3}, 4), # 4(a_1)^3 + Monomial({1: 2}, 3), # 3(a_1)^2 + Monomial({1: 1}, -2), # -2(a_1) + Monomial({}, 5) # +5 +]) + +divisor = Polynomial([ + Monomial({1: 1}, 2), # 2(a_1) + Monomial({}, -1) # -1 +]) + +quotient = dividend / divisor +print("Quotient:", quotient) diff --git a/tests/test_polynomial.py b/tests/test_polynomial.py index 4ba2ba6b7..ab5674017 100644 --- a/tests/test_polynomial.py +++ b/tests/test_polynomial.py @@ -105,27 +105,6 @@ def test_polynomial_multiplication(self): ])) return - def test_polynomial_division(self): - - # Should raise a ValueError if the divisor is not a monomial - # or a polynomial with only one term. - self.assertRaises(ValueError, lambda x, y: x / y, self.p5, self.p3) - self.assertRaises(ValueError, lambda x, y: x / y, self.p6, self.p4) - - self.assertEqual(self.p3 / self.p2, Polynomial([ - Monomial({}, 1), - Monomial({1: 1, 2: -1}, 0.75) - ])) - self.assertEqual(self.p7 / self.m1, Polynomial([ - Monomial({1: -1, 2: -3}, 2), - Monomial({1: 0, 2: -4}, 1.5) - ])) - self.assertEqual(self.p7 / self.m1, Polynomial([ - Monomial({1: -1, 2: -3}, 2), - Monomial({2: -4}, 1.5) - ])) - return - def test_polynomial_variables(self): # The zero polynomial has no variables. @@ -172,4 +151,51 @@ def test_polynomial_clone(self): self.assertEqual(self.p5.clone(), Polynomial([ Monomial({1: -1, 3: 2}, 1) ])) - return \ No newline at end of file + return + + def test_polynomial_long_division(self): + """ + Test polynomial long division + """ + + # Dividend: 4a_1^3 + 3a_1^2 - 2a_1 + 5 + dividend = Polynomial([ + Monomial({1: 3}, 4), # 4(a_1)^3 + Monomial({1: 2}, 3), # 3(a_1)^2 + Monomial({1: 1}, -2), # -2(a_1) + Monomial({}, 5) # +5 + ]) + + # Divisor: 2a_1 - 1 + divisor = Polynomial([ + Monomial({1: 1}, 2), # 2(a_1) + Monomial({}, -1) # -1 + ]) + + # Expected Quotient: 2a_1^2 + (5/2)a_1 + 1/4 + expected_quotient = Polynomial([ + Monomial({1: 2}, 2), # 2(a_1)^2 + Monomial({1: 1}, Fraction(5, 2)), # (5/2)(a_1) + Monomial({}, Fraction(1, 4)) # +1/4 + ]) + + # Expected Remainder: 21/4 + expected_remainder = Polynomial([ + Monomial({}, Fraction(21, 4)) # 21/4 + ]) + + quotient_long_div, remainder_long_div = dividend.poly_long_division(divisor) + + quotient_truediv = dividend / divisor # Calls __truediv__, which returns only the quotient + + # Check if quotient from poly_long_division matches expected + self.assertEqual(quotient_long_div, expected_quotient) + + # Check if remainder from poly_long_division matches expected + self.assertEqual(remainder_long_div, expected_remainder) + + # Check if quotient from __truediv__ matches quotient from poly_long_division + self.assertEqual(quotient_truediv, quotient_long_div) + + return + From 0b04e60364fe02dc04c5232f274286bcbbee1049 Mon Sep 17 00:00:00 2001 From: Chadndrabhan Patel <88890660+cpatel321@users.noreply.github.com> Date: Fri, 27 Jun 2025 11:00:17 +0530 Subject: [PATCH 301/302] Update test_array.py (missing comma at line 12) (#2047) --- tests/test_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_array.py b/tests/test_array.py index f1ad11693..b73ecb17b 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -9,7 +9,7 @@ missing_ranges, move_zeros, plus_one_v1, plus_one_v2, plus_one_v3, - remove_duplicates + remove_duplicates, rotate_v1, rotate_v2, rotate_v3, summarize_ranges, three_sum, From 486fa37782e956c28449b109ba6864ceb78a3972 Mon Sep 17 00:00:00 2001 From: shirleymaza <166472849+shirleymaza@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:30:32 -0400 Subject: [PATCH 302/302] Added Bead Sort Algorithm #920 (#2100) --- algorithms/sort/bead_sort.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 algorithms/sort/bead_sort.py diff --git a/algorithms/sort/bead_sort.py b/algorithms/sort/bead_sort.py new file mode 100644 index 000000000..0d949fa82 --- /dev/null +++ b/algorithms/sort/bead_sort.py @@ -0,0 +1,26 @@ +""" +Bead Sort (also known as Gravity Sort) is a natural sorting algorithm that simulates how beads would settle under gravity on an abacus. It is most useful for sorting positive integers, especially when the range of numbers isn't excessively large. However, it is not a comparison-based sort and is generally impractical for large inputs due to its reliance on physical modeling. +Time Complexity +- Best Case: O(n) if the numbers are already sorted +- Average Case: O(n^2) because each bead needs to be placed and then fall under gravity +- Worst Case: O(n^2) since each bead must "fall" individually +""" + +def bead_sort(arr): + if any(num < 0 for num in arr): + raise ValueError("Bead sort only works with non-negative integers.") + + max_num = max(arr) if arr else 0 + grid = [[0] * len(arr) for _ in range(max_num)] + + # Drop beads (place beads in columns) + for col, num in enumerate(arr): + for row in range(num): + grid[row][col] = 1 + + # Let the beads "fall" (count beads in each row) + for row in grid: + sum_beads = sum(row) + for col in range(len(arr)): + row[col] = 1 if col < sum_beads else 0 +