From 9a45c2f565ac218ab7b02aa741330a6a1713e4f7 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sat, 6 Aug 2022 17:26:59 +0430 Subject: [PATCH 01/10] Add `MaxFenwickTree` --- .../binary_tree/maximum_fenwick_tree.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 data_structures/binary_tree/maximum_fenwick_tree.py diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py new file mode 100644 index 000000000000..67a5455fcc50 --- /dev/null +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -0,0 +1,46 @@ +class MaxFenwickTree: + """ + Maximum Fenwick Tree + --------- + >>> ft = MaxFenwickTree(5) + >>> ft.query(0, 5) + 0 + >>> ft.update(2, 20) + >>> ft.query(0, 5) + 20 + >>> ft.update(5, 10) + >>> ft.query(2, 5) + 10 + >>> ft.update(2, 0) + >>> ft.query(0, 5) + 10 + """ + + def __init__(self, n: int): # Create Fenwick tree with size n + self.n = n + self.arr = [0] * (n + 1) + self.tree = [0] * (n + 1) + + def update(self, i, val) -> None: # Set value of index i (1-Based) to val in O(lg^2 N) + self.arr[i] = val + while i < self.n: + self.tree[i] = max(val, self.query(i, i - i & -i)) + i += i & (-i) + + def query(self, l, r) -> int: # Query maximum value from range (l, r] (1-Based) in O(lg N) + res = 0 + while l < r: + ll = r - r & -r + if l < ll: + res = max(res, self.tree[r]) + r = ll + else: + res = max(res, self.arr[r]) + r -= 1 + return res + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From 7d3111e5592c5936436b0f870d1605be0f4eeeb3 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sat, 6 Aug 2022 17:34:36 +0430 Subject: [PATCH 02/10] Reformat code style --- data_structures/binary_tree/maximum_fenwick_tree.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py index 67a5455fcc50..920c7dd1552a 100644 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -21,13 +21,17 @@ def __init__(self, n: int): # Create Fenwick tree with size n self.arr = [0] * (n + 1) self.tree = [0] * (n + 1) - def update(self, i, val) -> None: # Set value of index i (1-Based) to val in O(lg^2 N) + def update( + self, i, val + ) -> None: # Set value of index i (1-Based) to val in O(lg^2 N) self.arr[i] = val while i < self.n: self.tree[i] = max(val, self.query(i, i - i & -i)) i += i & (-i) - def query(self, l, r) -> int: # Query maximum value from range (l, r] (1-Based) in O(lg N) + def query( + self, l, r + ) -> int: # Query maximum value from range (l, r] (1-Based) in O(lg N) res = 0 while l < r: ll = r - r & -r From a3910c5f21cfe2fdd309f816cdd82ed8da307f60 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sat, 6 Aug 2022 17:45:22 +0430 Subject: [PATCH 03/10] Fix type hints --- .../binary_tree/maximum_fenwick_tree.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py index 920c7dd1552a..4345b3b0e267 100644 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -16,31 +16,31 @@ class MaxFenwickTree: 10 """ - def __init__(self, n: int): # Create Fenwick tree with size n + def __init__(self, n: int) -> None: # Create Fenwick tree with size n self.n = n self.arr = [0] * (n + 1) self.tree = [0] * (n + 1) def update( - self, i, val - ) -> None: # Set value of index i (1-Based) to val in O(lg^2 N) - self.arr[i] = val - while i < self.n: - self.tree[i] = max(val, self.query(i, i - i & -i)) - i += i & (-i) + self, index: int, value: int + ) -> None: # Set index (1-Based) to value in O(lg^2 N) + self.arr[index] = value + while index < self.n: + self.tree[index] = max(value, self.query(index, index - index & -index)) + index += index & (-index) def query( - self, l, r - ) -> int: # Query maximum value from range (l, r] (1-Based) in O(lg N) + self, left: int, right: int + ) -> int: # Query maximum value from range (left, right] (1-Based) in O(lg N) res = 0 - while l < r: - ll = r - r & -r - if l < ll: - res = max(res, self.tree[r]) - r = ll + while left < right: + x = right - right & -right + if left < x: + res = max(res, self.tree[right]) + right = x else: - res = max(res, self.arr[r]) - r -= 1 + res = max(res, self.arr[right]) + right -= 1 return res From b5249e7f55b8e75adbdc8f2f5500d2b75cf2b196 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sat, 6 Aug 2022 17:46:52 +0430 Subject: [PATCH 04/10] Fix type hints again --- data_structures/binary_tree/maximum_fenwick_tree.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py index 4345b3b0e267..bd9b83dd4b84 100644 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -16,16 +16,16 @@ class MaxFenwickTree: 10 """ - def __init__(self, n: int) -> None: # Create Fenwick tree with size n - self.n = n - self.arr = [0] * (n + 1) - self.tree = [0] * (n + 1) + def __init__(self, size: int) -> None: # Create Fenwick tree with specified size + self.size = size + self.arr = [0] * (size + 1) + self.tree = [0] * (size + 1) def update( self, index: int, value: int ) -> None: # Set index (1-Based) to value in O(lg^2 N) self.arr[index] = value - while index < self.n: + while index < self.size: self.tree[index] = max(value, self.query(index, index - index & -index)) index += index & (-index) From 4ee19a4c07fec3648a322e1fe04b930d175f45c5 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sat, 6 Aug 2022 22:02:01 +0430 Subject: [PATCH 05/10] Complete docstring --- .../binary_tree/maximum_fenwick_tree.py | 50 ------------ .../maximum_fenwick_tree_one_based_indexig.py | 79 +++++++++++++++++++ 2 files changed, 79 insertions(+), 50 deletions(-) delete mode 100644 data_structures/binary_tree/maximum_fenwick_tree.py create mode 100644 data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py deleted file mode 100644 index bd9b83dd4b84..000000000000 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ /dev/null @@ -1,50 +0,0 @@ -class MaxFenwickTree: - """ - Maximum Fenwick Tree - --------- - >>> ft = MaxFenwickTree(5) - >>> ft.query(0, 5) - 0 - >>> ft.update(2, 20) - >>> ft.query(0, 5) - 20 - >>> ft.update(5, 10) - >>> ft.query(2, 5) - 10 - >>> ft.update(2, 0) - >>> ft.query(0, 5) - 10 - """ - - def __init__(self, size: int) -> None: # Create Fenwick tree with specified size - self.size = size - self.arr = [0] * (size + 1) - self.tree = [0] * (size + 1) - - def update( - self, index: int, value: int - ) -> None: # Set index (1-Based) to value in O(lg^2 N) - self.arr[index] = value - while index < self.size: - self.tree[index] = max(value, self.query(index, index - index & -index)) - index += index & (-index) - - def query( - self, left: int, right: int - ) -> int: # Query maximum value from range (left, right] (1-Based) in O(lg N) - res = 0 - while left < right: - x = right - right & -right - if left < x: - res = max(res, self.tree[right]) - right = x - else: - res = max(res, self.arr[right]) - right -= 1 - return res - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py b/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py new file mode 100644 index 000000000000..9467f5f5ca3a --- /dev/null +++ b/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py @@ -0,0 +1,79 @@ +class MaxFenwickTreeOneBasedIndexing: + """ + Maximum Fenwick Tree with One-Based Indexing + --------- + >>> ft = MaxFenwickTreeOneBasedIndexing(5) + >>> ft.query(0, 5) + 0 + >>> ft.update(2, 20) + >>> ft.query(0, 5) + 20 + >>> ft.update(5, 10) + >>> ft.query(2, 5) + 10 + >>> ft.update(2, 0) + >>> ft.query(0, 5) + 10 + >>> ft = MaxFenwickTreeOneBasedIndexing(10000) + >>> ft.update(255, 30) + >>> ft.query(0, 10000) + 30 + """ + + def __init__(self, size: int) -> None: + """ + Create empty One-Based indexing Maximum Fenwick Tree with specified size + + Parameters: + size: size of Array + + Returns: + None + """ + self.size = size + self.arr = [0] * (size + 1) + self.tree = [0] * (size + 1) + + def update(self, index: int, value: int) -> None: + """ + Set index to value in O(lg^2 N) + + Parameters: + index: index to update + value: value to set + + Returns: + None + """ + self.arr[index] = value + while index < self.size: + self.tree[index] = max(value, self.query(index - index & -index, index)) + index += index & (-index) + + def query(self, left: int, right: int) -> int: + """ + Answer the query of maximum range (l, r] in O(lg^2 N) + + Parameters: + left: left index of query range (exclusive) + right: right index of query range (inclusive) + + Returns: + Maximum value of range (left, right] + """ + result = 0 + while left < right: + current_left = right - right & -right + if left < current_left: + result = max(result, self.tree[right]) + right = current_left + else: + result = max(result, self.arr[right]) + right -= 1 + return result + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From 9a058033754c37d979c56e2b908a6551603601c6 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sat, 6 Aug 2022 22:02:01 +0430 Subject: [PATCH 06/10] Complete docstring --- .../binary_tree/maximum_fenwick_tree.py | 50 ------------ .../maximum_fenwick_tree_one_based_indexig.py | 81 +++++++++++++++++++ 2 files changed, 81 insertions(+), 50 deletions(-) delete mode 100644 data_structures/binary_tree/maximum_fenwick_tree.py create mode 100644 data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py deleted file mode 100644 index bd9b83dd4b84..000000000000 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ /dev/null @@ -1,50 +0,0 @@ -class MaxFenwickTree: - """ - Maximum Fenwick Tree - --------- - >>> ft = MaxFenwickTree(5) - >>> ft.query(0, 5) - 0 - >>> ft.update(2, 20) - >>> ft.query(0, 5) - 20 - >>> ft.update(5, 10) - >>> ft.query(2, 5) - 10 - >>> ft.update(2, 0) - >>> ft.query(0, 5) - 10 - """ - - def __init__(self, size: int) -> None: # Create Fenwick tree with specified size - self.size = size - self.arr = [0] * (size + 1) - self.tree = [0] * (size + 1) - - def update( - self, index: int, value: int - ) -> None: # Set index (1-Based) to value in O(lg^2 N) - self.arr[index] = value - while index < self.size: - self.tree[index] = max(value, self.query(index, index - index & -index)) - index += index & (-index) - - def query( - self, left: int, right: int - ) -> int: # Query maximum value from range (left, right] (1-Based) in O(lg N) - res = 0 - while left < right: - x = right - right & -right - if left < x: - res = max(res, self.tree[right]) - right = x - else: - res = max(res, self.arr[right]) - right -= 1 - return res - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py b/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py new file mode 100644 index 000000000000..74e32df7570c --- /dev/null +++ b/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py @@ -0,0 +1,81 @@ +class MaxFenwickTreeOneBasedIndexing: + """ + Maximum Fenwick Tree with One-Based Indexing + + More info: https://cp-algorithms.com/data_structures/fenwick.html + --------- + >>> ft = MaxFenwickTreeOneBasedIndexing(5) + >>> ft.query(0, 5) + 0 + >>> ft.update(2, 20) + >>> ft.query(0, 5) + 20 + >>> ft.update(5, 10) + >>> ft.query(2, 5) + 10 + >>> ft.update(2, 0) + >>> ft.query(0, 5) + 10 + >>> ft = MaxFenwickTreeOneBasedIndexing(10000) + >>> ft.update(255, 30) + >>> ft.query(0, 10000) + 30 + """ + + def __init__(self, size: int) -> None: + """ + Create empty One-Based indexing Maximum Fenwick Tree with specified size + + Parameters: + size: size of Array + + Returns: + None + """ + self.size = size + self.arr = [0] * (size + 1) + self.tree = [0] * (size + 1) + + def update(self, index: int, value: int) -> None: + """ + Set index to value in O(lg^2 N) + + Parameters: + index: index to update + value: value to set + + Returns: + None + """ + self.arr[index] = value + while index < self.size: + self.tree[index] = max(value, self.query(index - index & -index, index)) + index += index & (-index) + + def query(self, left: int, right: int) -> int: + """ + Answer the query of maximum range (l, r] in O(lg^2 N) + + Parameters: + left: left index of query range (exclusive) + right: right index of query range (inclusive) + + Returns: + Maximum value of range (left, right] + """ + result = 0 + while left < right: + current_left = right - right & -right + if left < current_left: + result = max(result, self.tree[right]) + right = current_left + else: + result = max(result, self.arr[right]) + right -= 1 + return result + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From 4cc01755cc89bb56286b88a490fb97fec32091aa Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Sun, 7 Aug 2022 14:54:31 +0430 Subject: [PATCH 07/10] Fix typo in file name --- ...ased_indexig.py => maximum_fenwick_tree_one_based_indexing.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data_structures/binary_tree/{maximum_fenwick_tree_one_based_indexig.py => maximum_fenwick_tree_one_based_indexing.py} (100%) diff --git a/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py b/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexing.py similarity index 100% rename from data_structures/binary_tree/maximum_fenwick_tree_one_based_indexig.py rename to data_structures/binary_tree/maximum_fenwick_tree_one_based_indexing.py From 4fb0acedd9f54a6c650396e9b5194f274f8c9f5f Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Fri, 12 Aug 2022 10:29:09 +0430 Subject: [PATCH 08/10] Change MaxFenwickTree into 0-based indexing --- ...ed_indexing.py => maximum_fenwick_tree.py} | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) rename data_structures/binary_tree/{maximum_fenwick_tree_one_based_indexing.py => maximum_fenwick_tree.py} (56%) diff --git a/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexing.py b/data_structures/binary_tree/maximum_fenwick_tree.py similarity index 56% rename from data_structures/binary_tree/maximum_fenwick_tree_one_based_indexing.py rename to data_structures/binary_tree/maximum_fenwick_tree.py index 74e32df7570c..87ca4e4cc3e7 100644 --- a/data_structures/binary_tree/maximum_fenwick_tree_one_based_indexing.py +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -1,22 +1,22 @@ -class MaxFenwickTreeOneBasedIndexing: +class MaxFenwickTree: """ - Maximum Fenwick Tree with One-Based Indexing + Maximum Fenwick Tree More info: https://cp-algorithms.com/data_structures/fenwick.html --------- - >>> ft = MaxFenwickTreeOneBasedIndexing(5) + >>> ft = MaxFenwickTree(5) >>> ft.query(0, 5) 0 >>> ft.update(2, 20) >>> ft.query(0, 5) 20 - >>> ft.update(5, 10) + >>> ft.update(4, 10) >>> ft.query(2, 5) - 10 + 20 >>> ft.update(2, 0) >>> ft.query(0, 5) 10 - >>> ft = MaxFenwickTreeOneBasedIndexing(10000) + >>> ft = MaxFenwickTree(10000) >>> ft.update(255, 30) >>> ft.query(0, 10000) 30 @@ -24,7 +24,7 @@ class MaxFenwickTreeOneBasedIndexing: def __init__(self, size: int) -> None: """ - Create empty One-Based indexing Maximum Fenwick Tree with specified size + Create empty Maximum Fenwick Tree with specified size Parameters: size: size of Array @@ -36,6 +36,20 @@ def __init__(self, size: int) -> None: self.arr = [0] * (size + 1) self.tree = [0] * (size + 1) + @staticmethod + def get_next(index: int) -> int: + """ + Get next index in O(1) + """ + return index + index & -index + + @staticmethod + def get_prev(index: int) -> int: + """ + Get previous index in O(1) + """ + return index - index & -index + def update(self, index: int, value: int) -> None: """ Set index to value in O(lg^2 N) @@ -48,29 +62,30 @@ def update(self, index: int, value: int) -> None: None """ self.arr[index] = value + index += 1 # 1-indexed while index < self.size: - self.tree[index] = max(value, self.query(index - index & -index, index)) - index += index & (-index) + self.tree[index] = max(value, self.query(self.get_prev(index), index)) + index = self.get_next(index) def query(self, left: int, right: int) -> int: """ - Answer the query of maximum range (l, r] in O(lg^2 N) + Answer the query of maximum range [l, r) in O(lg^2 N) Parameters: - left: left index of query range (exclusive) - right: right index of query range (inclusive) + left: left index of query range (inclusive) + right: right index of query range (exclusive) Returns: - Maximum value of range (left, right] + Maximum value of range [left, right) """ result = 0 while left < right: - current_left = right - right & -right + current_left = self.get_prev(right) if left < current_left: result = max(result, self.tree[right]) right = current_left else: - result = max(result, self.arr[right]) + result = max(result, self.arr[right - 1]) # Because of right is exclusive right -= 1 return result From 8a72c0ebeea0d27d2d36826e395b69f4199f2ebc Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Fri, 12 Aug 2022 11:03:31 +0430 Subject: [PATCH 09/10] Fix Bugs --- data_structures/binary_tree/maximum_fenwick_tree.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py index 87ca4e4cc3e7..a40323176c92 100644 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -7,6 +7,10 @@ class MaxFenwickTree: >>> ft = MaxFenwickTree(5) >>> ft.query(0, 5) 0 + >>> ft.update(4, 100) + >>> ft.query(0, 5) + 100 + >>> ft.update(4, 0) >>> ft.update(2, 20) >>> ft.query(0, 5) 20 @@ -41,14 +45,14 @@ def get_next(index: int) -> int: """ Get next index in O(1) """ - return index + index & -index + return index + (index & -index) @staticmethod def get_prev(index: int) -> int: """ Get previous index in O(1) """ - return index - index & -index + return index - (index & -index) def update(self, index: int, value: int) -> None: """ @@ -63,7 +67,7 @@ def update(self, index: int, value: int) -> None: """ self.arr[index] = value index += 1 # 1-indexed - while index < self.size: + while index < self.size + 1: self.tree[index] = max(value, self.query(self.get_prev(index), index)) index = self.get_next(index) From 5fd80510d62140e1c538bc309a635557e4f49c67 Mon Sep 17 00:00:00 2001 From: AmirMohammad Hosseini Nasab Date: Fri, 12 Aug 2022 13:36:23 +0430 Subject: [PATCH 10/10] Minor fix --- data_structures/binary_tree/maximum_fenwick_tree.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/maximum_fenwick_tree.py b/data_structures/binary_tree/maximum_fenwick_tree.py index a40323176c92..e90bd634d51c 100644 --- a/data_structures/binary_tree/maximum_fenwick_tree.py +++ b/data_structures/binary_tree/maximum_fenwick_tree.py @@ -16,6 +16,8 @@ class MaxFenwickTree: 20 >>> ft.update(4, 10) >>> ft.query(2, 5) + 10 + >>> ft.query(1, 5) 20 >>> ft.update(2, 0) >>> ft.query(0, 5) @@ -37,8 +39,8 @@ def __init__(self, size: int) -> None: None """ self.size = size - self.arr = [0] * (size + 1) - self.tree = [0] * (size + 1) + self.arr = [0] * size + self.tree = [0] * size @staticmethod def get_next(index: int) -> int: @@ -66,8 +68,7 @@ def update(self, index: int, value: int) -> None: None """ self.arr[index] = value - index += 1 # 1-indexed - while index < self.size + 1: + while index < self.size: self.tree[index] = max(value, self.query(self.get_prev(index), index)) index = self.get_next(index) @@ -82,6 +83,7 @@ def query(self, left: int, right: int) -> int: Returns: Maximum value of range [left, right) """ + right -= 1 # Because of right is exclusive result = 0 while left < right: current_left = self.get_prev(right) @@ -89,7 +91,7 @@ def query(self, left: int, right: int) -> int: result = max(result, self.tree[right]) right = current_left else: - result = max(result, self.arr[right - 1]) # Because of right is exclusive + result = max(result, self.arr[right]) right -= 1 return result