From 79531e5bc8ffd94cb10d72fc370bef1761bc152c Mon Sep 17 00:00:00 2001 From: anirudnits Date: Wed, 25 Sep 2019 14:16:59 +0530 Subject: [PATCH 01/25] Added the matrix_exponentiation.py file in maths directory --- maths/matrix_exponentiation.py | 134 +++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 maths/matrix_exponentiation.py diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py new file mode 100644 index 000000000000..17b243baf7ca --- /dev/null +++ b/maths/matrix_exponentiation.py @@ -0,0 +1,134 @@ +"""Matrix Exponentiation""" + +import timeit + +""" +Matrix Exponentiation is a technique to solve linear recurrences in logarithmic time. +You read more about it here: +http://zobayer.blogspot.com/2010/11/matrix-exponentiation.html +https://www.hackerearth.com/practice/notes/matrix-exponentiation-1/ +""" + + +class Matrix(object): + def __init__(self, arg): + if isinstance(arg,list): #Initialzes a matrix identical to the one provided. + self.t = arg + self.n = len(arg) + + else: #Initializes a square matrix of the given size and set the values to zero. + self.n = arg + self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] + + def __mul__(self, b): + c = Matrix(self.n) + + for i in range(self.n): + for j in range(self.n): + for k in range(self.n): + c.t[i][j] += self.t[i][k]*b.t[k][j] + + return c + +def modular_exponentiation(a, b): + ret = Matrix([[1,0], [0,1]]) + + while b > 0: + if b&1: + ret = ret*a + + a = a*a + b >>= 1 + + return ret + +def fibonacci_with_matrix_exponentiation(n, f1, f2): + + #Trivial Cases + if n == 1: + return f1 + + if n == 2: + return f2 + + a = Matrix([[1,1], [1,0]]) + + m = modular_exponentiation(a, n-2) + + return f2*m.t[0][0] + f1*m.t[0][1] + +def simple_fibonacci(n, f1, f2): + + #Trival Cases + if n == 1: + return f1 + + if n == 2: + return f2 + + fn_1 = f1 + fn_2 = f2 + + n -= 2 + + while n > 0: + fn = fn_1 + fn_2 + + fn_2 = fn_1 + fn_1 = fn + + n -= 1 + + return fn + +def matrix_exponentiation_time(): + setup = ''' +from random import randint +from __main__ import fibonacci_with_matrix_exponentiation +''' + + code = ''' +n = randint(1,70000) + +f1 = 1 +f2 = 1 + + +fibonacci_with_matrix_exponentiation(n, f1, f2) +''' + exec_time = timeit.timeit(setup = setup, + stmt = code, + number = 100) + + print ("With matrix exponentiation the average execution time is ", exec_time/100) + + +def simple_fibonacci_time(): + setup = ''' +from random import randint +from __main__ import simple_fibonacci +''' + + code = ''' +n = randint(1,70000) + +f1 = 1 +f2 = 1 + + +simple_fibonacci(n, f1, f2) +''' + exec_time = timeit.timeit(setup = setup, + stmt = code, + number = 100) + + print ("Without matrix exponentiation the average execution time is ", exec_time/100) + + +def main(): + matrix_exponentiation_time() + simple_fibonacci_time() + + +if __name__ == "__main__": + main() \ No newline at end of file From f97cc0037da26aefccb5af11a795cdcb333bcd4f Mon Sep 17 00:00:00 2001 From: anirudnits Date: Wed, 25 Sep 2019 15:53:10 +0530 Subject: [PATCH 02/25] Implemented the requested changes --- maths/matrix_exponentiation.py | 138 ++++++++++++++++----------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index 17b243baf7ca..f2f2ad35b418 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -11,124 +11,122 @@ class Matrix(object): - def __init__(self, arg): - if isinstance(arg,list): #Initialzes a matrix identical to the one provided. - self.t = arg - self.n = len(arg) + def __init__(self, arg): + if isinstance(arg, list): # Initialzes a matrix identical to the one provided. + self.t = arg + self.n = len(arg) - else: #Initializes a square matrix of the given size and set the values to zero. - self.n = arg - self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] + else: # Initializes a square matrix of the given size and set the values to zero. + self.n = arg + self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] - def __mul__(self, b): - c = Matrix(self.n) + def __mul__(self, b): + c = Matrix(self.n) - for i in range(self.n): - for j in range(self.n): - for k in range(self.n): - c.t[i][j] += self.t[i][k]*b.t[k][j] + for i in range(self.n): + for j in range(self.n): + for k in range(self.n): + c.t[i][j] += self.t[i][k] * b.t[k][j] + + return c - return c def modular_exponentiation(a, b): - ret = Matrix([[1,0], [0,1]]) + ret = Matrix([[1, 0], [0, 1]]) + + while b > 0: + if b & 1: + ret = ret * a - while b > 0: - if b&1: - ret = ret*a + a = a * a + b >>= 1 - a = a*a - b >>= 1 + return ret - return ret def fibonacci_with_matrix_exponentiation(n, f1, f2): - - #Trivial Cases - if n == 1: - return f1 - if n == 2: - return f2 + # Trivial Cases + if n == 1: + return f1 + + if n == 2: + return f2 - a = Matrix([[1,1], [1,0]]) + a = Matrix([[1, 1], [1, 0]]) - m = modular_exponentiation(a, n-2) + m = modular_exponentiation(a, n - 2) + + return f2 * m.t[0][0] + f1 * m.t[0][1] - return f2*m.t[0][0] + f1*m.t[0][1] def simple_fibonacci(n, f1, f2): - #Trival Cases - if n == 1: - return f1 + # Trival Cases + if n == 1: + return f1 + + if n == 2: + return f2 - if n == 2: - return f2 + fn_1 = f1 + fn_2 = f2 - fn_1 = f1 - fn_2 = f2 + n -= 2 - n -= 2 + while n > 0: + fn = fn_1 + fn_2 - while n > 0: - fn = fn_1 + fn_2 + fn_2 = fn_1 + fn_1 = fn - fn_2 = fn_1 - fn_1 = fn + n -= 1 - n -= 1 + return fn - return fn def matrix_exponentiation_time(): - setup = ''' + setup = """ from random import randint from __main__ import fibonacci_with_matrix_exponentiation -''' - - code = ''' -n = randint(1,70000) +""" + code = """ f1 = 1 f2 = 1 -fibonacci_with_matrix_exponentiation(n, f1, f2) -''' - exec_time = timeit.timeit(setup = setup, - stmt = code, - number = 100) +fibonacci_with_matrix_exponentiation(randint(1,70000), f1, f2) +""" + exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - print ("With matrix exponentiation the average execution time is ", exec_time/100) + print("With matrix exponentiation the average execution time is ", exec_time / 100) def simple_fibonacci_time(): - setup = ''' + setup = """ from random import randint from __main__ import simple_fibonacci -''' - - code = ''' -n = randint(1,70000) +""" + code = """ f1 = 1 f2 = 1 -simple_fibonacci(n, f1, f2) -''' - exec_time = timeit.timeit(setup = setup, - stmt = code, - number = 100) +simple_fibonacci(randint(1,70000), f1, f2) +""" + exec_time = timeit.timeit(setup=setup, stmt=code, number=100) + + print( + "Without matrix exponentiation the average execution time is ", exec_time / 100 + ) - print ("Without matrix exponentiation the average execution time is ", exec_time/100) - def main(): - matrix_exponentiation_time() - simple_fibonacci_time() + matrix_exponentiation_time() + simple_fibonacci_time() if __name__ == "__main__": - main() \ No newline at end of file + main() From 8e64f021cc0ad35494bb130f77ec7a46d24f65b0 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 25 Sep 2019 20:08:29 +0200 Subject: [PATCH 03/25] Update matrix_exponentiation.py --- maths/matrix_exponentiation.py | 71 +++++++++------------------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index f2f2ad35b418..ee9e1757687c 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -15,71 +15,53 @@ def __init__(self, arg): if isinstance(arg, list): # Initialzes a matrix identical to the one provided. self.t = arg self.n = len(arg) - else: # Initializes a square matrix of the given size and set the values to zero. self.n = arg self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] def __mul__(self, b): - c = Matrix(self.n) - + matrix = Matrix(self.n) for i in range(self.n): for j in range(self.n): for k in range(self.n): - c.t[i][j] += self.t[i][k] * b.t[k][j] - - return c + matrix.t[i][j] += self.t[i][k] * b.t[k][j] + return matrix def modular_exponentiation(a, b): - ret = Matrix([[1, 0], [0, 1]]) - + matrix = Matrix([[1, 0], [0, 1]]) while b > 0: if b & 1: - ret = ret * a - - a = a * a + matrix *= a + a *= a b >>= 1 - - return ret + return matrix def fibonacci_with_matrix_exponentiation(n, f1, f2): - # Trivial Cases if n == 1: return f1 - - if n == 2: + elif n == 2: return f2 - - a = Matrix([[1, 1], [1, 0]]) - - m = modular_exponentiation(a, n - 2) - - return f2 * m.t[0][0] + f1 * m.t[0][1] + matrix = Matrix([[1, 1], [1, 0]]) + matrix = modular_exponentiation(matrix, n - 2) + return f2 * matrix.t[0][0] + f1 * matrix.t[0][1] def simple_fibonacci(n, f1, f2): - # Trival Cases if n == 1: return f1 - - if n == 2: + elif n == 2: return f2 fn_1 = f1 fn_2 = f2 - n -= 2 while n > 0: - fn = fn_1 + fn_2 - - fn_2 = fn_1 - fn_1 = fn - + fn_1, fn_2 = fn_1 + fn_2, fn_1 n -= 1 return fn @@ -90,17 +72,10 @@ def matrix_exponentiation_time(): from random import randint from __main__ import fibonacci_with_matrix_exponentiation """ - - code = """ -f1 = 1 -f2 = 1 - - -fibonacci_with_matrix_exponentiation(randint(1,70000), f1, f2) -""" + code = "fibonacci_with_matrix_exponentiation(randint(1,70000), 1, 1)" exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - print("With matrix exponentiation the average execution time is ", exec_time / 100) + return exec_time def simple_fibonacci_time(): @@ -108,19 +83,11 @@ def simple_fibonacci_time(): from random import randint from __main__ import simple_fibonacci """ - - code = """ -f1 = 1 -f2 = 1 - - -simple_fibonacci(randint(1,70000), f1, f2) -""" + code = "simple_fibonacci(randint(1,70000), 1, 1)" exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - - print( - "Without matrix exponentiation the average execution time is ", exec_time / 100 - ) + print("Without matrix exponentiation the average execution time is ", + exec_time / 100) + return exec_time def main(): From f21e0c171e03b425ce5214d3abf81b8c70445a3e Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sun, 14 Mar 2021 14:41:39 +0530 Subject: [PATCH 04/25] resolve merge conflict with upstream branch --- maths/matrix_exponentiation.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index a0cf03e74761..3cb220e14a0a 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -51,7 +51,6 @@ def fibonacci_with_matrix_exponentiation(n, f1, f2): def simple_fibonacci(n, f1, f2): # Trivial Cases - if n == 1: return f1 elif n == 2: @@ -86,11 +85,9 @@ def simple_fibonacci_time(): """ code = "simple_fibonacci(randint(1,70000), 1, 1)" exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - print( "Without matrix exponentiation the average execution time is ", exec_time / 100 ) - return exec_time @@ -100,4 +97,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file From fe050d763fbbe2160b794f72d81b00ec9547fee0 Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sun, 14 Mar 2021 15:01:43 +0530 Subject: [PATCH 05/25] add new line at end of file --- maths/matrix_exponentiation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index 3cb220e14a0a..033ceb3f28a0 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -97,4 +97,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() From 5cb7a26846c607aa26a7b8ef5dac3603cf65d749 Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sun, 14 Mar 2021 15:02:08 +0530 Subject: [PATCH 06/25] add wavelet_tree --- data_structures/binary_tree/wavelet_tree.py | 192 ++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 data_structures/binary_tree/wavelet_tree.py diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py new file mode 100644 index 000000000000..78192c6ceff5 --- /dev/null +++ b/data_structures/binary_tree/wavelet_tree.py @@ -0,0 +1,192 @@ +from typing import List, Optional + + +""" +Wavelet tree is a data-structure designed to efficiently answer various range queries +for arrays. Wavelets trees are different from other binary trees in the sense that +the nodes are split based on the actual values of the elements and not on indices, +such as the with segment trees or fenwick trees. You can read more about them here: +1. https://users.dcc.uchile.cl/~jperez/papers/ioiconf16.pdf +2. https://www.youtube.com/watch?v=4aSv9PcecDw&t=811s +3. https://www.youtube.com/watch?v=CybAgVF-MMc&t=1178s +""" + + +class Node: + def __init__(self, n): + self.minn: int = -1 + self.maxx: int = -1 + self.map_left: List = [-1] * n + self.left: Optional[Node] = None + self.right: Optional[Node] = None + + def __repr__(self): + return f"min_value: {self.minn}, max_value: {self.maxx}" + + +def build_tree(arr: List[int]) -> Node: + """ + Builds the tree for the provided list arr and returns the root + of the constructed tree. + """ + + n = len(arr) + + root = Node(n) + + root.minn, root.maxx = min(arr), max(arr) + + # Leaf node case where the node contains only one unique value + if root.minn == root.maxx: + return root + + """ + Take the mean of min and max element as the pivot and + partition arr into left_arr and right_arr with all elements <= pivot in the + left_arr and the rest in right_arr, maintaining the order of the elements, + then recursively build trees for left_arr and right_arr + """ + + pivot = (root.minn + root.maxx) // 2 + left_arr, right_arr = [], [] + + for index, num in enumerate(arr): + if num <= pivot: + left_arr.append(num) + else: + right_arr.append(num) + + root.map_left[index] = len(left_arr) + + root.left = build_tree(left_arr) + root.right = build_tree(right_arr) + + return root + + +def rank_from_start(node: Node, num: int, i: int) -> int: + """ + Returns the number of occurances of num in interval [0, i] in the list + """ + if i < 0: + return 0 + + # Leaf node cases + if node.minn == node.maxx: + if node.minn == num: + return i + 1 + else: + return 0 + + pivot = (node.minn + node.maxx) // 2 + + if ( + num <= pivot + ): # if num <= pivot, go the left subtree and map index i to the left subtree + return rank_from_start(node.left, num, node.map_left[i] - 1) + else: # otherwise go to the right subtree and map index i to the right subtree + return rank_from_start(node.right, num, i - node.map_left[i]) + + +def rank(node: Node, num: int, i: int, j: int) -> int: + """ + Returns the number of occurances of num in interval [i, j] in the list + """ + if i > j: + return 0 + + rank_till_j = rank_from_start(node, num, j) # rank of num in interval [0, j] + rank_before_i = rank_from_start( + node, num, i - 1 + ) # rank of num in interval [0, i-1] + + return rank_till_j - rank_before_i + + +def quantile(node: Node, k: int, i: int, j: int) -> int: + """ + Returns the kth smallest element in interval [i, j] in the list, k is 0-indexed + """ + if k > (j - i) or i > j: + return -1 + + # Leaf node case + if node.minn == node.maxx: + return node.minn + + # number of elements in the left subtree in interval [i, j] + num_elements_in_left_tree = node.map_left[j] - (node.map_left[i - 1] if i else 0) + + if num_elements_in_left_tree > k: + return quantile( + node.left, k, (node.map_left[i - 1] if i else 0), node.map_left[j] - 1 + ) + else: + return quantile( + node.right, + k - num_elements_in_left_tree, + i - (node.map_left[i - 1] if i else 0), + j - node.map_left[j], + ) + + +def range_counting(node: Node, i: int, j: int, x: int, y: int) -> int: + """ + Returns the number of elememts in range [x,y] in interval [i, j] in the list + """ + if i > j or x > y: + return 0 + + if node.minn > y or node.maxx < x: + return 0 + + if x <= node.minn and node.maxx <= y: + return j - i + 1 + + left = range_counting( + node.left, (node.map_left[i - 1] if i else 0), node.map_left[j] - 1, x, y + ) + right = range_counting( + node.right, i - (node.map_left[i - 1] if i else 0), j - node.map_left[j], x, y + ) + + return left + right + + +def main(): + """ + >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] + >>> root = build_tree(arr) + >>> root + min_value: 1, max_value: 9 + >>> rank(root, 6, 3, 13) + 3 + >>> rank(root, 2, 0, 17) + 4 + >>> rank(root, 9, 2 ,2) + 0 + >>> quantile(root, 2, 2, 5) + 6 + >>> quantile(root, 4, 2, 13) + 4 + >>> quantile(root, 0, 6, 6) + 9 + >>> quantile(root, 4, 2, 5) + -1 + >>> range_counting(root, 1, 10, 3, 7) + 5 + >>> range_counting(root, 2, 2, 1, 4) + 1 + >>> range_counting(root, 0, 17, 1, 100) + 18 + >>> range_counting(root, 1, 0, 1, 100) + 0 + >>> range_counting(root, 0, 17, 100, 1) + 0 + """ + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From d6dfb71fe1db9096e61a3b57e54d0aa026252e19 Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sun, 14 Mar 2021 15:03:38 +0530 Subject: [PATCH 07/25] fix isort issue --- data_structures/binary_tree/wavelet_tree.py | 1 - 1 file changed, 1 deletion(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 78192c6ceff5..7bb49b719ace 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -1,6 +1,5 @@ from typing import List, Optional - """ Wavelet tree is a data-structure designed to efficiently answer various range queries for arrays. Wavelets trees are different from other binary trees in the sense that From 58df1d4121e32360e9b59f72e2aba59e7ffe0c7f Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 14 Mar 2021 09:36:14 +0000 Subject: [PATCH 08/25] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index dfb673dea829..1ae600065aa1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -133,6 +133,7 @@ * [Segment Tree](https://github.com/TheAlgorithms/Python/blob/master/data_structures/binary_tree/segment_tree.py) * [Segment Tree Other](https://github.com/TheAlgorithms/Python/blob/master/data_structures/binary_tree/segment_tree_other.py) * [Treap](https://github.com/TheAlgorithms/Python/blob/master/data_structures/binary_tree/treap.py) + * [Wavelet Tree](https://github.com/TheAlgorithms/Python/blob/master/data_structures/binary_tree/wavelet_tree.py) * Disjoint Set * [Alternate Disjoint Set](https://github.com/TheAlgorithms/Python/blob/master/data_structures/disjoint_set/alternate_disjoint_set.py) * [Disjoint Set](https://github.com/TheAlgorithms/Python/blob/master/data_structures/disjoint_set/disjoint_set.py) @@ -472,6 +473,7 @@ * [Runge Kutta](https://github.com/TheAlgorithms/Python/blob/master/maths/runge_kutta.py) * [Segmented Sieve](https://github.com/TheAlgorithms/Python/blob/master/maths/segmented_sieve.py) * Series + * [Arithmetic Mean](https://github.com/TheAlgorithms/Python/blob/master/maths/series/arithmetic_mean.py) * [Geometric Mean](https://github.com/TheAlgorithms/Python/blob/master/maths/series/geometric_mean.py) * [Geometric Series](https://github.com/TheAlgorithms/Python/blob/master/maths/series/geometric_series.py) * [Harmonic Series](https://github.com/TheAlgorithms/Python/blob/master/maths/series/harmonic_series.py) From 49f7d6d328851acd2612573b8806e39145a81d97 Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sun, 14 Mar 2021 15:31:03 +0530 Subject: [PATCH 09/25] fix variable names in wavelet_tree and correct typo --- data_structures/binary_tree/wavelet_tree.py | 82 ++++++++++++--------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 7bb49b719ace..e2b56c36dbdb 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -12,10 +12,10 @@ class Node: - def __init__(self, n): + def __init__(self, length): self.minn: int = -1 self.maxx: int = -1 - self.map_left: List = [-1] * n + self.map_left: List = [-1] * length self.left: Optional[Node] = None self.right: Optional[Node] = None @@ -25,8 +25,8 @@ def __repr__(self): def build_tree(arr: List[int]) -> Node: """ - Builds the tree for the provided list arr and returns the root - of the constructed tree. + Builds the tree for arr and returns the root + of the constructed tree """ n = len(arr) @@ -40,7 +40,7 @@ def build_tree(arr: List[int]) -> Node: return root """ - Take the mean of min and max element as the pivot and + Take the mean of min and max element of arr as the pivot and partition arr into left_arr and right_arr with all elements <= pivot in the left_arr and the rest in right_arr, maintaining the order of the elements, then recursively build trees for left_arr and right_arr @@ -63,17 +63,17 @@ def build_tree(arr: List[int]) -> Node: return root -def rank_from_start(node: Node, num: int, i: int) -> int: +def rank_from_start(node: Node, num: int, index: int) -> int: """ - Returns the number of occurances of num in interval [0, i] in the list + Returns the number of occurrences of num in interval [0, index] in the list """ - if i < 0: + if index < 0: return 0 # Leaf node cases if node.minn == node.maxx: if node.minn == num: - return i + 1 + return index + 1 else: return 0 @@ -82,77 +82,91 @@ def rank_from_start(node: Node, num: int, i: int) -> int: if ( num <= pivot ): # if num <= pivot, go the left subtree and map index i to the left subtree - return rank_from_start(node.left, num, node.map_left[i] - 1) + return rank_from_start(node.left, num, node.map_left[index] - 1) else: # otherwise go to the right subtree and map index i to the right subtree - return rank_from_start(node.right, num, i - node.map_left[i]) + return rank_from_start(node.right, num, index - node.map_left[index]) -def rank(node: Node, num: int, i: int, j: int) -> int: +def rank(node: Node, num: int, start: int, end: int) -> int: """ - Returns the number of occurances of num in interval [i, j] in the list + Returns the number of occurrences of num in interval [start, end] in the list """ - if i > j: + if start > end: return 0 - rank_till_j = rank_from_start(node, num, j) # rank of num in interval [0, j] - rank_before_i = rank_from_start( - node, num, i - 1 - ) # rank of num in interval [0, i-1] + rank_till_end = rank_from_start(node, num, end) # rank of num in interval [0, end] + rank_before_start = rank_from_start( + node, num, start - 1 + ) # rank of num in interval [0, start-1] - return rank_till_j - rank_before_i + return rank_till_end - rank_before_start -def quantile(node: Node, k: int, i: int, j: int) -> int: +def quantile(node: Node, k: int, start: int, end: int) -> int: """ - Returns the kth smallest element in interval [i, j] in the list, k is 0-indexed + Returns the kth smallest element in interval [start, end] in the list + k is 0-indexed """ - if k > (j - i) or i > j: + if k > (end - start) or start > end: return -1 # Leaf node case if node.minn == node.maxx: return node.minn - # number of elements in the left subtree in interval [i, j] - num_elements_in_left_tree = node.map_left[j] - (node.map_left[i - 1] if i else 0) + # Number of elements in the left subtree in interval [start, end] + num_elements_in_left_tree = node.map_left[end] - ( + node.map_left[start - 1] if start else 0 + ) if num_elements_in_left_tree > k: return quantile( - node.left, k, (node.map_left[i - 1] if i else 0), node.map_left[j] - 1 + node.left, + k, + (node.map_left[start - 1] if start else 0), + node.map_left[end] - 1, ) else: return quantile( node.right, k - num_elements_in_left_tree, - i - (node.map_left[i - 1] if i else 0), - j - node.map_left[j], + start - (node.map_left[start - 1] if start else 0), + end - node.map_left[end], ) -def range_counting(node: Node, i: int, j: int, x: int, y: int) -> int: +def range_counting(node: Node, start: int, end: int, x: int, y: int) -> int: """ - Returns the number of elememts in range [x,y] in interval [i, j] in the list + Returns the number of elememts in range [x,y] in interval [start, end] in the list """ - if i > j or x > y: + if start > end or x > y: return 0 if node.minn > y or node.maxx < x: return 0 if x <= node.minn and node.maxx <= y: - return j - i + 1 + return end - start + 1 left = range_counting( - node.left, (node.map_left[i - 1] if i else 0), node.map_left[j] - 1, x, y + node.left, + (node.map_left[start - 1] if start else 0), + node.map_left[end] - 1, + x, + y, ) right = range_counting( - node.right, i - (node.map_left[i - 1] if i else 0), j - node.map_left[j], x, y + node.right, + start - (node.map_left[start - 1] if start else 0), + end - node.map_left[end], + x, + y, ) return left + right -def main(): +def main() -> None: """ >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] >>> root = build_tree(arr) From 5de688b622a17d42592ed27465d437d5c1c52106 Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sun, 14 Mar 2021 17:09:22 +0530 Subject: [PATCH 10/25] Add type hints and variable renaming --- data_structures/binary_tree/wavelet_tree.py | 44 +++++++++++---------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index e2b56c36dbdb..07e19281ef76 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -12,14 +12,14 @@ class Node: - def __init__(self, length): + def __init__(self, length: int) -> None: self.minn: int = -1 self.maxx: int = -1 self.map_left: List = [-1] * length self.left: Optional[Node] = None self.right: Optional[Node] = None - def __repr__(self): + def __repr__(self) -> str: return f"min_value: {self.minn}, max_value: {self.maxx}" @@ -28,7 +28,6 @@ def build_tree(arr: List[int]) -> Node: Builds the tree for arr and returns the root of the constructed tree """ - n = len(arr) root = Node(n) @@ -81,9 +80,9 @@ def rank_from_start(node: Node, num: int, index: int) -> int: if ( num <= pivot - ): # if num <= pivot, go the left subtree and map index i to the left subtree + ): # if num <= pivot, go the left subtree and map index to the left subtree return rank_from_start(node.left, num, node.map_left[index] - 1) - else: # otherwise go to the right subtree and map index i to the right subtree + else: # otherwise go to the right subtree and map index to the right subtree return rank_from_start(node.right, num, index - node.map_left[index]) @@ -102,12 +101,12 @@ def rank(node: Node, num: int, start: int, end: int) -> int: return rank_till_end - rank_before_start -def quantile(node: Node, k: int, start: int, end: int) -> int: +def quantile(node: Node, index: int, start: int, end: int) -> int: """ - Returns the kth smallest element in interval [start, end] in the list - k is 0-indexed + Returns the index'th smallest element in interval [start, end] in the list + index is 0-indexed """ - if k > (end - start) or start > end: + if index > (end - start) or start > end: return -1 # Leaf node case @@ -119,48 +118,51 @@ def quantile(node: Node, k: int, start: int, end: int) -> int: node.map_left[start - 1] if start else 0 ) - if num_elements_in_left_tree > k: + if num_elements_in_left_tree > index: return quantile( node.left, - k, + index, (node.map_left[start - 1] if start else 0), node.map_left[end] - 1, ) else: return quantile( node.right, - k - num_elements_in_left_tree, + index - num_elements_in_left_tree, start - (node.map_left[start - 1] if start else 0), end - node.map_left[end], ) -def range_counting(node: Node, start: int, end: int, x: int, y: int) -> int: +def range_counting( + node: Node, start: int, end: int, start_num: int, end_num: int +) -> int: """ - Returns the number of elememts in range [x,y] in interval [start, end] in the list + Returns the number of elememts in range [start_num, end_num] + in interval [start, end] in the list """ - if start > end or x > y: + if start > end or start_num > end_num: return 0 - if node.minn > y or node.maxx < x: + if node.minn > end_num or node.maxx < start_num: return 0 - if x <= node.minn and node.maxx <= y: + if start_num <= node.minn and node.maxx <= end_num: return end - start + 1 left = range_counting( node.left, (node.map_left[start - 1] if start else 0), node.map_left[end] - 1, - x, - y, + start_num, + end_num, ) right = range_counting( node.right, start - (node.map_left[start - 1] if start else 0), end - node.map_left[end], - x, - y, + start_num, + end_num, ) return left + right From b96aefe130346059aa83eacd910cf5ce8b1a97a7 Mon Sep 17 00:00:00 2001 From: Aniruddha Bhattacharjee Date: Sat, 27 Mar 2021 16:28:55 +0530 Subject: [PATCH 11/25] Update data_structures/binary_tree/wavelet_tree.py Add doctests to placate the algorithm-bot, thanks to @cclauss. Co-authored-by: Christian Clauss --- data_structures/binary_tree/wavelet_tree.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 07e19281ef76..967a40783511 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -20,6 +20,13 @@ def __init__(self, length: int) -> None: self.right: Optional[Node] = None def __repr__(self) -> str: + """ + >>> node = Node(length=27) + >>> repr(node) + 'min_value: -1, max_value: -1' + >>> repr(node) == str(node) + True + """ return f"min_value: {self.minn}, max_value: {self.maxx}" From 688bcb3c2d7c92f1573d43b8c877db07c1d3839c Mon Sep 17 00:00:00 2001 From: anirudnits Date: Sat, 27 Mar 2021 21:52:47 +0530 Subject: [PATCH 12/25] Move doctest to individual functions and reformat code --- data_structures/binary_tree/wavelet_tree.py | 107 +++++++++++--------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 967a40783511..8033e90c7d5f 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -34,6 +34,11 @@ def build_tree(arr: List[int]) -> Node: """ Builds the tree for arr and returns the root of the constructed tree + + >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] + >>> root = build_tree(arr) + >>> root + min_value: 1, max_value: 9 """ n = len(arr) @@ -69,41 +74,56 @@ def build_tree(arr: List[int]) -> Node: return root -def rank_from_start(node: Node, num: int, index: int) -> int: +def rank_till_index(node: Node, num: int, index: int) -> int: """ Returns the number of occurrences of num in interval [0, index] in the list + + >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] + >>> root = build_tree(arr) + >>> rank_till_index(root, 6, 6) + 1 + >>> rank_till_index(root, 2, 0) + 1 + >>> rank_till_index(root, 1, 10) + 2 + >>> rank_till_index(root, 17, 7) + 0 """ if index < 0: return 0 # Leaf node cases if node.minn == node.maxx: - if node.minn == num: - return index + 1 - else: - return 0 + return index + 1 if node.minn == num else 0 pivot = (node.minn + node.maxx) // 2 - if ( - num <= pivot - ): # if num <= pivot, go the left subtree and map index to the left subtree - return rank_from_start(node.left, num, node.map_left[index] - 1) - else: # otherwise go to the right subtree and map index to the right subtree - return rank_from_start(node.right, num, index - node.map_left[index]) + if num <= pivot: + # go the left subtree and map index to the left subtree + return rank_till_index(node.left, num, node.map_left[index] - 1) + else: + # go to the right subtree and map index to the right subtree + return rank_till_index(node.right, num, index - node.map_left[index]) def rank(node: Node, num: int, start: int, end: int) -> int: """ Returns the number of occurrences of num in interval [start, end] in the list + + >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] + >>> root = build_tree(arr) + >>> rank(root, 6, 3, 13) + 3 + >>> rank(root, 2, 0, 17) + 4 + >>> rank(root, 9, 2 ,2) + 0 """ if start > end: return 0 - rank_till_end = rank_from_start(node, num, end) # rank of num in interval [0, end] - rank_before_start = rank_from_start( - node, num, start - 1 - ) # rank of num in interval [0, start-1] + rank_till_end = rank_till_index(node, num, end) + rank_before_start = rank_till_index(node, num, start - 1) return rank_till_end - rank_before_start @@ -112,6 +132,17 @@ def quantile(node: Node, index: int, start: int, end: int) -> int: """ Returns the index'th smallest element in interval [start, end] in the list index is 0-indexed + + >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] + >>> root = build_tree(arr) + >>> quantile(root, 2, 2, 5) + 6 + >>> quantile(root, 4, 2, 13) + 4 + >>> quantile(root, 0, 6, 6) + 9 + >>> quantile(root, 4, 2, 5) + -1 """ if index > (end - start) or start > end: return -1 @@ -147,6 +178,19 @@ def range_counting( """ Returns the number of elememts in range [start_num, end_num] in interval [start, end] in the list + + >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] + >>> root = build_tree(arr) + >>> range_counting(root, 1, 10, 3, 7) + 5 + >>> range_counting(root, 2, 2, 1, 4) + 1 + >>> range_counting(root, 0, 17, 1, 100) + 18 + >>> range_counting(root, 1, 0, 1, 100) + 0 + >>> range_counting(root, 0, 17, 100, 1) + 0 """ if start > end or start_num > end_num: return 0 @@ -175,39 +219,6 @@ def range_counting( return left + right -def main() -> None: - """ - >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] - >>> root = build_tree(arr) - >>> root - min_value: 1, max_value: 9 - >>> rank(root, 6, 3, 13) - 3 - >>> rank(root, 2, 0, 17) - 4 - >>> rank(root, 9, 2 ,2) - 0 - >>> quantile(root, 2, 2, 5) - 6 - >>> quantile(root, 4, 2, 13) - 4 - >>> quantile(root, 0, 6, 6) - 9 - >>> quantile(root, 4, 2, 5) - -1 - >>> range_counting(root, 1, 10, 3, 7) - 5 - >>> range_counting(root, 2, 2, 1, 4) - 1 - >>> range_counting(root, 0, 17, 1, 100) - 18 - >>> range_counting(root, 1, 0, 1, 100) - 0 - >>> range_counting(root, 0, 17, 100, 1) - 0 - """ - - if __name__ == "__main__": import doctest From b93ddafd20ac16fc81e0b9a7ee1988eb39daed82 Mon Sep 17 00:00:00 2001 From: Aniruddha Bhattacharjee Date: Mon, 5 Apr 2021 23:02:59 +0530 Subject: [PATCH 13/25] Move common test array to the global scope and reuse in tests --- data_structures/binary_tree/wavelet_tree.py | 39 ++++++++++----------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 8033e90c7d5f..c51aa6f78909 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -35,10 +35,9 @@ def build_tree(arr: List[int]) -> Node: Builds the tree for arr and returns the root of the constructed tree - >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] - >>> root = build_tree(arr) + >>> root = build_tree(test_array) >>> root - min_value: 1, max_value: 9 + min_value: 0, max_value: 9 """ n = len(arr) @@ -78,8 +77,7 @@ def rank_till_index(node: Node, num: int, index: int) -> int: """ Returns the number of occurrences of num in interval [0, index] in the list - >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] - >>> root = build_tree(arr) + >>> root = build_tree(test_array) >>> rank_till_index(root, 6, 6) 1 >>> rank_till_index(root, 2, 0) @@ -88,6 +86,8 @@ def rank_till_index(node: Node, num: int, index: int) -> int: 2 >>> rank_till_index(root, 17, 7) 0 + >>> rank_till_index(root, 0, 9) + 1 """ if index < 0: return 0 @@ -110,14 +110,15 @@ def rank(node: Node, num: int, start: int, end: int) -> int: """ Returns the number of occurrences of num in interval [start, end] in the list - >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] - >>> root = build_tree(arr) + >>> root = build_tree(test_array) >>> rank(root, 6, 3, 13) - 3 - >>> rank(root, 2, 0, 17) + 2 + >>> rank(root, 2, 0, 19) 4 >>> rank(root, 9, 2 ,2) 0 + >>> rank(root, 0, 5, 10) + 2 """ if start > end: return 0 @@ -133,14 +134,13 @@ def quantile(node: Node, index: int, start: int, end: int) -> int: Returns the index'th smallest element in interval [start, end] in the list index is 0-indexed - >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] - >>> root = build_tree(arr) + >>> root = build_tree(test_array) >>> quantile(root, 2, 2, 5) - 6 - >>> quantile(root, 4, 2, 13) + 5 + >>> quantile(root, 5, 2, 13) 4 >>> quantile(root, 0, 6, 6) - 9 + 8 >>> quantile(root, 4, 2, 5) -1 """ @@ -179,14 +179,13 @@ def range_counting( Returns the number of elememts in range [start_num, end_num] in interval [start, end] in the list - >>> arr = [2,1,4,5,6,8,9,1,2,6,7,4,2,6,5,3,2,7] - >>> root = build_tree(arr) + >>> root = build_tree(test_array) >>> range_counting(root, 1, 10, 3, 7) - 5 + 3 >>> range_counting(root, 2, 2, 1, 4) 1 - >>> range_counting(root, 0, 17, 1, 100) - 18 + >>> range_counting(root, 0, 19, 0, 100) + 20 >>> range_counting(root, 1, 0, 1, 100) 0 >>> range_counting(root, 0, 17, 100, 1) @@ -222,4 +221,4 @@ def range_counting( if __name__ == "__main__": import doctest - doctest.testmod() + doctest.testmod(extraglobs={"test_array": [2,1,4,5,6,0,8,9,1,2,0,6,4,2,0,6,5,3,2,7]}) From a829cb7dc3bcf561901e04edfee462a2ba9a0cec Mon Sep 17 00:00:00 2001 From: Aniruddha Date: Mon, 5 Apr 2021 23:11:46 +0530 Subject: [PATCH 14/25] MMove test array to global scope and minor linting changes --- data_structures/binary_tree/wavelet_tree.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index c51aa6f78909..d495c9a5fe99 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -221,4 +221,8 @@ def range_counting( if __name__ == "__main__": import doctest - doctest.testmod(extraglobs={"test_array": [2,1,4,5,6,0,8,9,1,2,0,6,4,2,0,6,5,3,2,7]}) + doctest.testmod( + extraglobs={ + "test_array": [2, 1, 4, 5, 6, 0, 8, 9, 1, 2, 0, 6, 4, 2, 0, 6, 5, 3, 2, 7] + } + ) From 4403f70e6c569d0377a610a311f4aaa27447dd8c Mon Sep 17 00:00:00 2001 From: Aniruddha Date: Tue, 6 Apr 2021 12:30:26 +0530 Subject: [PATCH 15/25] Correct the failing pytest tests --- data_structures/binary_tree/wavelet_tree.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index d495c9a5fe99..64998835ce2b 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -10,6 +10,8 @@ 3. https://www.youtube.com/watch?v=CybAgVF-MMc&t=1178s """ +test_array = [2, 1, 4, 5, 6, 0, 8, 9, 1, 2, 0, 6, 4, 2, 0, 6, 5, 3, 2, 7] + class Node: def __init__(self, length: int) -> None: @@ -221,8 +223,4 @@ def range_counting( if __name__ == "__main__": import doctest - doctest.testmod( - extraglobs={ - "test_array": [2, 1, 4, 5, 6, 0, 8, 9, 1, 2, 0, 6, 4, 2, 0, 6, 5, 3, 2, 7] - } - ) + doctest.testmod() From eda9f31e35e012d04e0763e13d69853b71cdb1a1 Mon Sep 17 00:00:00 2001 From: Aniruddha Date: Tue, 6 Apr 2021 20:03:55 +0530 Subject: [PATCH 16/25] MUse built-in list for type annotation --- data_structures/binary_tree/wavelet_tree.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 64998835ce2b..3ef8181c22d6 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional """ Wavelet tree is a data-structure designed to efficiently answer various range queries @@ -17,7 +17,7 @@ class Node: def __init__(self, length: int) -> None: self.minn: int = -1 self.maxx: int = -1 - self.map_left: List = [-1] * length + self.map_left: list[int] = [-1] * length self.left: Optional[Node] = None self.right: Optional[Node] = None @@ -32,13 +32,12 @@ def __repr__(self) -> str: return f"min_value: {self.minn}, max_value: {self.maxx}" -def build_tree(arr: List[int]) -> Node: +def build_tree(arr: list[int]) -> Node: """ Builds the tree for arr and returns the root of the constructed tree - >>> root = build_tree(test_array) - >>> root + >>> build_tree(test_array) min_value: 0, max_value: 9 """ n = len(arr) From 27b7fe117bb334c6cbe1dfd033282e094ef3d9fe Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:03:06 +0200 Subject: [PATCH 17/25] Update wavelet_tree.py --- data_structures/binary_tree/wavelet_tree.py | 35 ++++----------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 3ef8181c22d6..99636796f4b6 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -1,5 +1,3 @@ -from typing import Optional - """ Wavelet tree is a data-structure designed to efficiently answer various range queries for arrays. Wavelets trees are different from other binary trees in the sense that @@ -10,6 +8,8 @@ 3. https://www.youtube.com/watch?v=CybAgVF-MMc&t=1178s """ +from typing import Optional + test_array = [2, 1, 4, 5, 6, 0, 8, 9, 1, 2, 0, 6, 4, 2, 0, 6, 5, 3, 2, 7] @@ -40,37 +40,27 @@ def build_tree(arr: list[int]) -> Node: >>> build_tree(test_array) min_value: 0, max_value: 9 """ - n = len(arr) - - root = Node(n) - + root = Node(len(arr)) root.minn, root.maxx = min(arr), max(arr) - # Leaf node case where the node contains only one unique value if root.minn == root.maxx: return root - """ Take the mean of min and max element of arr as the pivot and partition arr into left_arr and right_arr with all elements <= pivot in the left_arr and the rest in right_arr, maintaining the order of the elements, then recursively build trees for left_arr and right_arr """ - pivot = (root.minn + root.maxx) // 2 left_arr, right_arr = [], [] - for index, num in enumerate(arr): if num <= pivot: left_arr.append(num) else: right_arr.append(num) - root.map_left[index] = len(left_arr) - root.left = build_tree(left_arr) root.right = build_tree(right_arr) - return root @@ -92,13 +82,10 @@ def rank_till_index(node: Node, num: int, index: int) -> int: """ if index < 0: return 0 - # Leaf node cases if node.minn == node.maxx: return index + 1 if node.minn == num else 0 - pivot = (node.minn + node.maxx) // 2 - if num <= pivot: # go the left subtree and map index to the left subtree return rank_till_index(node.left, num, node.map_left[index] - 1) @@ -123,10 +110,8 @@ def rank(node: Node, num: int, start: int, end: int) -> int: """ if start > end: return 0 - rank_till_end = rank_till_index(node, num, end) rank_before_start = rank_till_index(node, num, start - 1) - return rank_till_end - rank_before_start @@ -147,16 +132,13 @@ def quantile(node: Node, index: int, start: int, end: int) -> int: """ if index > (end - start) or start > end: return -1 - # Leaf node case if node.minn == node.maxx: return node.minn - # Number of elements in the left subtree in interval [start, end] num_elements_in_left_tree = node.map_left[end] - ( node.map_left[start - 1] if start else 0 ) - if num_elements_in_left_tree > index: return quantile( node.left, @@ -192,15 +174,11 @@ def range_counting( >>> range_counting(root, 0, 17, 100, 1) 0 """ - if start > end or start_num > end_num: - return 0 - - if node.minn > end_num or node.maxx < start_num: - return 0 - + if (start > end or start_num > end_num or node.minn > end_num + or node.maxx < start_num): + return 0 if start_num <= node.minn and node.maxx <= end_num: return end - start + 1 - left = range_counting( node.left, (node.map_left[start - 1] if start else 0), @@ -215,7 +193,6 @@ def range_counting( start_num, end_num, ) - return left + right From 1cfd9471d3b1f23689e8bef5c97b92b72519da1f Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:07:41 +0200 Subject: [PATCH 18/25] types-requests --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 349d88944656..8cb90419617e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,4 +14,5 @@ sklearn statsmodels sympy tensorflow; python_version < '3.9' +types-requests xgboost From 05e261dfe50140bc720a382a18aa17b8b56a04c4 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 8 Jun 2021 20:12:08 +0000 Subject: [PATCH 19/25] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 4b7d6a9322c6..e5ca6d62fe45 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -233,6 +233,7 @@ ## Dynamic Programming * [Abbreviation](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/abbreviation.py) * [Bitmask](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/bitmask.py) + * [Catalan Numbers](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/catalan_numbers.py) * [Climbing Stairs](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/climbing_stairs.py) * [Edit Distance](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/edit_distance.py) * [Factorial](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/factorial.py) From f20ba34a45f84095ab18e03004aeafec627e714b Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:15:03 +0200 Subject: [PATCH 20/25] Update wavelet_tree.py --- data_structures/binary_tree/wavelet_tree.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/data_structures/binary_tree/wavelet_tree.py b/data_structures/binary_tree/wavelet_tree.py index 99636796f4b6..1607244f74ed 100644 --- a/data_structures/binary_tree/wavelet_tree.py +++ b/data_structures/binary_tree/wavelet_tree.py @@ -174,9 +174,13 @@ def range_counting( >>> range_counting(root, 0, 17, 100, 1) 0 """ - if (start > end or start_num > end_num or node.minn > end_num - or node.maxx < start_num): - return 0 + if ( + start > end + or start_num > end_num + or node.minn > end_num + or node.maxx < start_num + ): + return 0 if start_num <= node.minn and node.maxx <= end_num: return end - start + 1 left = range_counting( From b02a6fdb71eb5b89f746a842a8827156f6adf5a1 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:21:05 +0200 Subject: [PATCH 21/25] # type: ignore --- scripts/validate_solutions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/validate_solutions.py b/scripts/validate_solutions.py index 68461dca6710..ca4af5261a8f 100755 --- a/scripts/validate_solutions.py +++ b/scripts/validate_solutions.py @@ -21,7 +21,7 @@ def convert_path_to_module(file_path: pathlib.Path) -> ModuleType: """Converts a file path to a Python module""" spec = importlib.util.spec_from_file_location(file_path.name, str(file_path)) - module = importlib.util.module_from_spec(spec) + module = importlib.util.module_from_spec(spec) # type: ignore spec.loader.exec_module(module) # type: ignore return module From e798b75be302d5c0739fc345c1f4c7e1e3903bcc Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:23:26 +0200 Subject: [PATCH 22/25] # type: ignore --- ciphers/decrypt_caesar_with_chi_squared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ciphers/decrypt_caesar_with_chi_squared.py b/ciphers/decrypt_caesar_with_chi_squared.py index e7faeae73773..b3ddc451d01f 100644 --- a/ciphers/decrypt_caesar_with_chi_squared.py +++ b/ciphers/decrypt_caesar_with_chi_squared.py @@ -222,7 +222,7 @@ def decrypt_caesar_with_chi_squared( # Get the most likely cipher by finding the cipher with the smallest chi squared # statistic - most_likely_cipher: int = min( + most_likely_cipher: int = min( # type: ignore chi_squared_statistic_values, key=chi_squared_statistic_values.get ) # type: ignore # First argument to `min` is not optional From 2317d72423ebf1d97f609e55be2b8ce64261200c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:30:58 +0200 Subject: [PATCH 23/25] Update decrypt_caesar_with_chi_squared.py --- ciphers/decrypt_caesar_with_chi_squared.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ciphers/decrypt_caesar_with_chi_squared.py b/ciphers/decrypt_caesar_with_chi_squared.py index b3ddc451d01f..b118dc7b053b 100644 --- a/ciphers/decrypt_caesar_with_chi_squared.py +++ b/ciphers/decrypt_caesar_with_chi_squared.py @@ -222,9 +222,10 @@ def decrypt_caesar_with_chi_squared( # Get the most likely cipher by finding the cipher with the smallest chi squared # statistic - most_likely_cipher: int = min( # type: ignore - chi_squared_statistic_values, key=chi_squared_statistic_values.get - ) # type: ignore # First argument to `min` is not optional + most_likely_cipher: int = min( + chi_squared_statistic_values, # type: ignore + key=chi_squared_statistic_values.get + ) # Get all the data from the most likely cipher (key, decoded message) ( From 9ea6c1cd4d09814655afe7bc25c536ddd61299ba Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:32:29 +0200 Subject: [PATCH 24/25] , --- ciphers/decrypt_caesar_with_chi_squared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ciphers/decrypt_caesar_with_chi_squared.py b/ciphers/decrypt_caesar_with_chi_squared.py index b118dc7b053b..e00c7b5fe39c 100644 --- a/ciphers/decrypt_caesar_with_chi_squared.py +++ b/ciphers/decrypt_caesar_with_chi_squared.py @@ -224,7 +224,7 @@ def decrypt_caesar_with_chi_squared( # statistic most_likely_cipher: int = min( chi_squared_statistic_values, # type: ignore - key=chi_squared_statistic_values.get + key=chi_squared_statistic_values.get, ) # Get all the data from the most likely cipher (key, decoded message) From ced6008e18e3018e7c323acc1a49c5ddeb0cc489 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 8 Jun 2021 22:41:00 +0200 Subject: [PATCH 25/25] Update decrypt_caesar_with_chi_squared.py --- ciphers/decrypt_caesar_with_chi_squared.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ciphers/decrypt_caesar_with_chi_squared.py b/ciphers/decrypt_caesar_with_chi_squared.py index e00c7b5fe39c..7e3705b8f71f 100644 --- a/ciphers/decrypt_caesar_with_chi_squared.py +++ b/ciphers/decrypt_caesar_with_chi_squared.py @@ -222,10 +222,10 @@ def decrypt_caesar_with_chi_squared( # Get the most likely cipher by finding the cipher with the smallest chi squared # statistic - most_likely_cipher: int = min( + most_likely_cipher: int = min( # type: ignore chi_squared_statistic_values, # type: ignore - key=chi_squared_statistic_values.get, - ) + key=chi_squared_statistic_values.get, # type: ignore + ) # type: ignore # Get all the data from the most likely cipher (key, decoded message) (