From 0457860ed491521b02d1559a76874d3e766823c0 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 13:21:16 +0530 Subject: [PATCH 01/26] Suffix Array and LCP Array Implementation --- divide_and_conquer/suffix_array_lcp.py | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 divide_and_conquer/suffix_array_lcp.py diff --git a/divide_and_conquer/suffix_array_lcp.py b/divide_and_conquer/suffix_array_lcp.py new file mode 100644 index 000000000000..c78acf49cdac --- /dev/null +++ b/divide_and_conquer/suffix_array_lcp.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +def build_suffix_array(s: str) -> list[int]: + """ + Build the suffix array for the given string. + + Parameters: + s (str): The input string. + + Returns: + list[int]: The suffix array (a list of starting indices of + suffixes in sorted order). + """ + suffixes = [(s[i:], i) for i in range(len(s))] + suffixes.sort() # Sort the suffixes lexicographically + suffix_array = [suffix[1] for suffix in suffixes] + return suffix_array + +def build_lcp_array(s: str, suffix_array: list[int]) -> list[int]: + """ + Build the LCP array for the given string and suffix array. + + Parameters: + s (str): The input string. + suffix_array (list[int]): The suffix array. + + Returns: + list[int]: The LCP array. + """ + n = len(s) + rank = [0] * n + lcp = [0] * n + + # Compute the rank of each suffix + for i, suffix_index in enumerate(suffix_array): + rank[suffix_index] = i + + # Compute the LCP array + h = 0 + for i in range(n): + if rank[i] > 0: + j = suffix_array[rank[i] - 1] + while (i + h < n) and (j + h < n) and (s[i + h] == s[j + h]): + h += 1 + lcp[rank[i]] = h + if h > 0: + h -= 1 # Decrease h for the next suffix + return lcp + +# Example usage +if __name__ == "__main__": + s = "banana" + suffix_array = build_suffix_array(s) + lcp_array = build_lcp_array(s, suffix_array) + + print("Suffix Array:") + for i in range(len(suffix_array)): + print(f"{suffix_array[i]}: {s[suffix_array[i]:]}") + + print("\nLCP Array:") + for i in range(1, len(lcp_array)): + print(f"LCP between {s[suffix_array[i - 1]:]} and {s[suffix_array[i]]}: {lcp_array[i]}") From 465cea3cbb59fcde7fb54550d44570b37b1bd174 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:55:36 +0530 Subject: [PATCH 02/26] Delete divide_and_conquer/suffix_array_lcp.py --- divide_and_conquer/suffix_array_lcp.py | 62 -------------------------- 1 file changed, 62 deletions(-) delete mode 100644 divide_and_conquer/suffix_array_lcp.py diff --git a/divide_and_conquer/suffix_array_lcp.py b/divide_and_conquer/suffix_array_lcp.py deleted file mode 100644 index c78acf49cdac..000000000000 --- a/divide_and_conquer/suffix_array_lcp.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 - -def build_suffix_array(s: str) -> list[int]: - """ - Build the suffix array for the given string. - - Parameters: - s (str): The input string. - - Returns: - list[int]: The suffix array (a list of starting indices of - suffixes in sorted order). - """ - suffixes = [(s[i:], i) for i in range(len(s))] - suffixes.sort() # Sort the suffixes lexicographically - suffix_array = [suffix[1] for suffix in suffixes] - return suffix_array - -def build_lcp_array(s: str, suffix_array: list[int]) -> list[int]: - """ - Build the LCP array for the given string and suffix array. - - Parameters: - s (str): The input string. - suffix_array (list[int]): The suffix array. - - Returns: - list[int]: The LCP array. - """ - n = len(s) - rank = [0] * n - lcp = [0] * n - - # Compute the rank of each suffix - for i, suffix_index in enumerate(suffix_array): - rank[suffix_index] = i - - # Compute the LCP array - h = 0 - for i in range(n): - if rank[i] > 0: - j = suffix_array[rank[i] - 1] - while (i + h < n) and (j + h < n) and (s[i + h] == s[j + h]): - h += 1 - lcp[rank[i]] = h - if h > 0: - h -= 1 # Decrease h for the next suffix - return lcp - -# Example usage -if __name__ == "__main__": - s = "banana" - suffix_array = build_suffix_array(s) - lcp_array = build_lcp_array(s, suffix_array) - - print("Suffix Array:") - for i in range(len(suffix_array)): - print(f"{suffix_array[i]}: {s[suffix_array[i]:]}") - - print("\nLCP Array:") - for i in range(1, len(lcp_array)): - print(f"LCP between {s[suffix_array[i - 1]:]} and {s[suffix_array[i]]}: {lcp_array[i]}") From 8ab292751c50cf330e9253402d335006304d43e0 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:58:29 +0530 Subject: [PATCH 03/26] Add files via upload --- data_structures/persistent_segment_tree.py | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 data_structures/persistent_segment_tree.py diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py new file mode 100644 index 000000000000..8963b54a2ba6 --- /dev/null +++ b/data_structures/persistent_segment_tree.py @@ -0,0 +1,80 @@ +class Node: + def __init__(self, value: int = 0) -> None: + self.value = value + self.left = None + self.right = None + + +class PersistentSegmentTree: + def __init__(self, arr: list[int]) -> None: + self.n = len(arr) + self.roots: list[Node] = [] + self.roots.append(self._build(arr, 0, self.n - 1)) + + def _build(self, arr: list[int], start: int, end: int) -> Node: + """ + Builds a segment tree from the provided array. + + >>> pst = PersistentSegmentTree([1, 2, 3]) + >>> root = pst._build([1, 2, 3], 0, 2) + >>> root.value # Sum of the whole array + 6 + """ + if start == end: + return Node(arr[start]) + mid = (start + end) // 2 + node = Node() + node.left = self._build(arr, start, mid) + node.right = self._build(arr, mid + 1, end) + node.value = node.left.value + node.right.value + return node + + def update(self, version: int, index: int, value: int) -> int: + """ + Updates the segment tree with a new value at the specified index. + + >>> pst = PersistentSegmentTree([1, 2, 3]) + >>> version_1 = pst.update(0, 1, 5) + >>> pst.query(version_1, 0, 2) # Query sum from index 0 to 2 + 9 + """ + new_root = self._update(self.roots[version], 0, self.n - 1, index, value) + self.roots.append(new_root) + return len(self.roots) - 1 # return the index of the new version + + def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: + if start == end: + new_node = Node(value) + return new_node + mid = (start + end) // 2 + new_node = Node() + if index <= mid: + new_node.left = self._update(node.left, start, mid, index, value) + new_node.right = node.right + else: + new_node.left = node.left + new_node.right = self._update(node.right, mid + 1, end, index, value) + new_node.value = new_node.left.value + new_node.right.value + return new_node + + def query(self, version: int, left: int, right: int) -> int: + """ + Queries the sum in the given range for the specified version. + + >>> pst = PersistentSegmentTree([1, 2, 3]) + >>> version_1 = pst.update(0, 1, 5) + >>> pst.query(version_1, 0, 1) # Query sum from index 0 to 1 + 6 + >>> pst.query(version_1, 0, 2) # Query sum from index 0 to 2 + 9 + """ + return self._query(self.roots[version], 0, self.n - 1, left, right) + + def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: + if left > end or right < start: + return 0 + if left <= start and right >= end: + return node.value + mid = (start + end) // 2 + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) From f5d380aafb63f7f676ff00dfd651ba3c691daac0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:30:45 +0000 Subject: [PATCH 04/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 8963b54a2ba6..7d7851071612 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -76,5 +76,6 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) From 819fdc88360a83d6d451c1ac501db54a9f6208b3 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:16:21 +0530 Subject: [PATCH 05/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 48 +++++++++++++--------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 7d7851071612..5bcf1f64d80e 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -7,19 +7,18 @@ def __init__(self, value: int = 0) -> None: class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: - self.n = len(arr) - self.roots: list[Node] = [] - self.roots.append(self._build(arr, 0, self.n - 1)) - - def _build(self, arr: list[int], start: int, end: int) -> Node: """ - Builds a segment tree from the provided array. + Initialize the Persistent Segment Tree with the given array. >>> pst = PersistentSegmentTree([1, 2, 3]) - >>> root = pst._build([1, 2, 3], 0, 2) - >>> root.value # Sum of the whole array + >>> pst.query(0, 0, 2) 6 """ + self.n = len(arr) + self.roots: list[Node] = [] + self.roots.append(self._build(arr, 0, self.n - 1)) + + def _build(self, arr: list[int], start: int, end: int) -> Node: if start == end: return Node(arr[start]) mid = (start + end) // 2 @@ -31,41 +30,46 @@ def _build(self, arr: list[int], start: int, end: int) -> Node: def update(self, version: int, index: int, value: int) -> int: """ - Updates the segment tree with a new value at the specified index. + Update the value at the given index and return the new version. >>> pst = PersistentSegmentTree([1, 2, 3]) >>> version_1 = pst.update(0, 1, 5) - >>> pst.query(version_1, 0, 2) # Query sum from index 0 to 2 + >>> pst.query(version_1, 0, 2) 9 """ new_root = self._update(self.roots[version], 0, self.n - 1, index, value) self.roots.append(new_root) - return len(self.roots) - 1 # return the index of the new version + return len(self.roots) - 1 def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: if start == end: - new_node = Node(value) - return new_node + return Node(value) + mid = (start + end) // 2 new_node = Node() + if index <= mid: new_node.left = self._update(node.left, start, mid, index, value) new_node.right = node.right else: new_node.left = node.left new_node.right = self._update(node.right, mid + 1, end, index, value) + new_node.value = new_node.left.value + new_node.right.value + return new_node def query(self, version: int, left: int, right: int) -> int: """ - Queries the sum in the given range for the specified version. + Query the sum in the given range for the specified version. >>> pst = PersistentSegmentTree([1, 2, 3]) + >>> pst.query(0, 0, 2) + 6 >>> version_1 = pst.update(0, 1, 5) - >>> pst.query(version_1, 0, 1) # Query sum from index 0 to 1 + >>> pst.query(version_1, 0, 1) 6 - >>> pst.query(version_1, 0, 2) # Query sum from index 0 to 2 + >>> pst.query(version_1, 0, 2) 9 """ return self._query(self.roots[version], 0, self.n - 1, left, right) @@ -76,6 +80,12 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) + + +if __name__ == "__main__": + import doctest + print("Running doctests...") + result = doctest.testmod() + print(f"Ran {result.attempted} tests, {result.failed} failed.") From 5de61840107d734cdc44b3b11602dbc53e41e7b5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:47:29 +0000 Subject: [PATCH 06/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 5bcf1f64d80e..24a44d90a4b3 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -80,12 +80,14 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 82270b7c636b42533099f7ac4069590c752a71ee Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:19:23 +0530 Subject: [PATCH 07/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 73 +++++++++++++--------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 24a44d90a4b3..bc65603480c5 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -7,18 +7,23 @@ def __init__(self, value: int = 0) -> None: class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: - """ - Initialize the Persistent Segment Tree with the given array. - - >>> pst = PersistentSegmentTree([1, 2, 3]) - >>> pst.query(0, 0, 2) - 6 - """ self.n = len(arr) self.roots: list[Node] = [] self.roots.append(self._build(arr, 0, self.n - 1)) def _build(self, arr: list[int], start: int, end: int) -> Node: + """ + Builds a segment tree from the provided array. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> root = pst._build([1, 2, 3, 4], 0, 3) + >>> root.value # Sum of the whole array + 10 + >>> root.left.value # Sum of the left half + 3 + >>> root.right.value # Sum of the right half + 7 + """ if start == end: return Node(arr[start]) mid = (start + end) // 2 @@ -29,19 +34,26 @@ def _build(self, arr: list[int], start: int, end: int) -> Node: return node def update(self, version: int, index: int, value: int) -> int: - """ - Update the value at the given index and return the new version. - - >>> pst = PersistentSegmentTree([1, 2, 3]) - >>> version_1 = pst.update(0, 1, 5) - >>> pst.query(version_1, 0, 2) - 9 - """ new_root = self._update(self.roots[version], 0, self.n - 1, index, value) self.roots.append(new_root) return len(self.roots) - 1 def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: + """ + Updates the node for the specified index and value and returns the new node. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> old_root = pst.roots[0] + >>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5 + >>> new_root.value # New sum after update + 13 + >>> old_root.value # Old root remains unchanged + 10 + >>> new_root.left.value # Updated left child + 6 + >>> new_root.right.value # Right child remains the same + 7 + """ if start == end: return Node(value) @@ -60,34 +72,33 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N return new_node def query(self, version: int, left: int, right: int) -> int: - """ - Query the sum in the given range for the specified version. - - >>> pst = PersistentSegmentTree([1, 2, 3]) - >>> pst.query(0, 0, 2) - 6 - >>> version_1 = pst.update(0, 1, 5) - >>> pst.query(version_1, 0, 1) - 6 - >>> pst.query(version_1, 0, 2) - 9 - """ return self._query(self.roots[version], 0, self.n - 1, left, right) def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: + """ + Queries the sum of values in the range [left, right] for the given node. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> root = pst.roots[0] + >>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2 + 5 + >>> pst._query(root, 0, 3, 0, 3) # Sum of all elements + 10 + >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3 + 7 + """ if left > end or right < start: return 0 if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) +# Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From ff5a9b81c4620701b1264f6c4d9875833588dfe7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:50:37 +0000 Subject: [PATCH 08/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index bc65603480c5..32f1ec0df0a7 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -92,13 +92,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 04b44c4c7b78aabf2acad2e59d4a64c405ded94b Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:22:59 +0530 Subject: [PATCH 09/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 33 +++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 32f1ec0df0a7..b0bc7ed3faa4 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -34,6 +34,19 @@ def _build(self, arr: list[int], start: int, end: int) -> Node: return node def update(self, version: int, index: int, value: int) -> int: + """ + Updates the value at the given index and returns the new version. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 + >>> pst.query(version_1, 0, 3) # Query sum of all elements in new version + 13 + >>> pst.query(0, 0, 3) # Original version remains unchanged + 10 + >>> version_2 = pst.update(version_1, 3, 6) # Update index 3 to 6 in version_1 + >>> pst.query(version_2, 0, 3) # Query sum of all elements in newest version + 15 + """ new_root = self._update(self.roots[version], 0, self.n - 1, index, value) self.roots.append(new_root) return len(self.roots) - 1 @@ -72,6 +85,20 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N return new_node def query(self, version: int, left: int, right: int) -> int: + """ + Queries the sum in the given range for the specified version. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> pst.query(0, 0, 3) # Sum of all elements in original version + 10 + >>> pst.query(0, 1, 2) # Sum of elements at index 1 and 2 in original version + 5 + >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 + >>> pst.query(version_1, 0, 3) # Sum of all elements in new version + 13 + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 in new version + 8 + """ return self._query(self.roots[version], 0, self.n - 1, left, right) def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: @@ -92,15 +119,13 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 0f5718fa688a17a0917841d14111adabc3fe149d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:54:28 +0000 Subject: [PATCH 10/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index b0bc7ed3faa4..884075437416 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -119,13 +119,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From eb9e2b73c6bd31ce4cc9f6233b23c3cddd16bf18 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:27:52 +0530 Subject: [PATCH 11/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 884075437416..e3a8427917fe 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,17 +1,18 @@ +from typing import List, Optional + class Node: def __init__(self, value: int = 0) -> None: - self.value = value - self.left = None - self.right = None - + self.value: int = value + self.left: Optional[Node] = None + self.right: Optional[Node] = None class PersistentSegmentTree: - def __init__(self, arr: list[int]) -> None: - self.n = len(arr) - self.roots: list[Node] = [] + def __init__(self, arr: List[int]) -> None: + self.n: int = len(arr) + self.roots: List[Node] = [] self.roots.append(self._build(arr, 0, self.n - 1)) - def _build(self, arr: list[int], start: int, end: int) -> Node: + def _build(self, arr: List[int], start: int, end: int) -> Node: """ Builds a segment tree from the provided array. @@ -119,15 +120,12 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 5c605df8b239599ba70df7a25291381e945ab38b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:58:52 +0000 Subject: [PATCH 12/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index e3a8427917fe..f7d0bdbbc87f 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from typing import List, Optional + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Optional[Node] = None self.right: Optional[Node] = None + class PersistentSegmentTree: def __init__(self, arr: List[int]) -> None: self.n: int = len(arr) @@ -120,12 +122,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 55e6a87625f10ca2abd8cc4460ae7fa0bd1ed228 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:43:40 +0530 Subject: [PATCH 13/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 24 +++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index f7d0bdbbc87f..4b1670819955 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,20 +1,18 @@ -from typing import List, Optional - +from __future__ import annotations class Node: def __init__(self, value: int = 0) -> None: self.value: int = value - self.left: Optional[Node] = None - self.right: Optional[Node] = None - + self.left: Node | None = None + self.right: Node | None = None class PersistentSegmentTree: - def __init__(self, arr: List[int]) -> None: + def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) - self.roots: List[Node] = [] + self.roots: list[Node] = [] self.roots.append(self._build(arr, 0, self.n - 1)) - def _build(self, arr: List[int], start: int, end: int) -> Node: + def _build(self, arr: list[int], start: int, end: int) -> Node: """ Builds a segment tree from the provided array. @@ -83,7 +81,8 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + new_node.right.value + new_node.value = (new_node.left.value if new_node.left else 0) + \ + (new_node.right.value if new_node.right else 0) return new_node @@ -122,15 +121,12 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From eaafd1ca3c99f6e97b8fc6026c470d81c4e7d023 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:14:53 +0000 Subject: [PATCH 14/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 4b1670819955..e153deff5ef4 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -81,8 +83,9 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = (new_node.left.value if new_node.left else 0) + \ - (new_node.right.value if new_node.right else 0) + new_node.value = (new_node.left.value if new_node.left else 0) + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -121,12 +124,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 124b177795957b010560b10f497c8a627ab28f47 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:49:21 +0530 Subject: [PATCH 15/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index e153deff5ef4..074e137bb366 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,13 +1,11 @@ from __future__ import annotations - class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None - class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -78,14 +76,12 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N if index <= mid: new_node.left = self._update(node.left, start, mid, index, value) - new_node.right = node.right + new_node.right = node.right # Ensure right node is the same as the original else: - new_node.left = node.left + new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = (new_node.left.value if new_node.left else 0) + ( - new_node.right.value if new_node.right else 0 - ) + new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) return new_node @@ -101,7 +97,7 @@ def query(self, version: int, left: int, right: int) -> int: >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 >>> pst.query(version_1, 0, 3) # Sum of all elements in new version 13 - >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 in new version + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) @@ -119,20 +115,17 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3 7 """ - if left > end or right < start: + if node is None or left > end or right < start: return 0 if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 902ed932ad9969889cbc15953253c2ad6e979d72 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:20:24 +0000 Subject: [PATCH 16/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 074e137bb366..05194fa20a4a 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -81,7 +83,9 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) + new_node.value = new_node.left.value + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -97,7 +101,7 @@ def query(self, version: int, left: int, right: int) -> int: >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 >>> pst.query(version_1, 0, 3) # Sum of all elements in new version 13 - >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) @@ -120,12 +124,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From f64233ad898dd65578411c2d33e803bb258e013a Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:54:55 +0530 Subject: [PATCH 17/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 54 ++++++---------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 05194fa20a4a..8b579b3b2cd2 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,13 +1,11 @@ from __future__ import annotations - class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None - class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -54,22 +52,10 @@ def update(self, version: int, index: int, value: int) -> int: self.roots.append(new_root) return len(self.roots) - 1 - def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: - """ - Updates the node for the specified index and value and returns the new node. + def _update(self, node: Node | None, start: int, end: int, index: int, value: int) -> Node: + if node is None: + raise ValueError("Cannot update a None node") - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> old_root = pst.roots[0] - >>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5 - >>> new_root.value # New sum after update - 13 - >>> old_root.value # Old root remains unchanged - 10 - >>> new_root.left.value # Updated left child - 6 - >>> new_root.right.value # Right child remains the same - 7 - """ if start == end: return Node(value) @@ -78,14 +64,12 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N if index <= mid: new_node.left = self._update(node.left, start, mid, index, value) - new_node.right = node.right # Ensure right node is the same as the original + new_node.right = node.right else: - new_node.left = node.left # Ensure left node is the same as the original + new_node.left = node.left new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + ( - new_node.right.value if new_node.right else 0 - ) + new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) return new_node @@ -101,38 +85,26 @@ def query(self, version: int, left: int, right: int) -> int: >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 >>> pst.query(version_1, 0, 3) # Sum of all elements in new version 13 - >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 in new version 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) - def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: - """ - Queries the sum of values in the range [left, right] for the given node. + def _query(self, node: Node | None, start: int, end: int, left: int, right: int) -> int: + if node is None: + return 0 - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> root = pst.roots[0] - >>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2 - 5 - >>> pst._query(root, 0, 3, 0, 3) # Sum of all elements - 10 - >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3 - 7 - """ - if node is None or left > end or right < start: + if left > end or right < start: return 0 if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 4484382444dee69e4af3f4b61d913928cdb944e0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:25:59 +0000 Subject: [PATCH 18/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 8b579b3b2cd2..cf6dbed0dbd9 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -52,7 +54,9 @@ def update(self, version: int, index: int, value: int) -> int: self.roots.append(new_root) return len(self.roots) - 1 - def _update(self, node: Node | None, start: int, end: int, index: int, value: int) -> Node: + def _update( + self, node: Node | None, start: int, end: int, index: int, value: int + ) -> Node: if node is None: raise ValueError("Cannot update a None node") @@ -69,7 +73,9 @@ def _update(self, node: Node | None, start: int, end: int, index: int, value: in new_node.left = node.left new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) + new_node.value = new_node.left.value + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -90,7 +96,9 @@ def query(self, version: int, left: int, right: int) -> int: """ return self._query(self.roots[version], 0, self.n - 1, left, right) - def _query(self, node: Node | None, start: int, end: int, left: int, right: int) -> int: + def _query( + self, node: Node | None, start: int, end: int, left: int, right: int + ) -> int: if node is None: return 0 @@ -99,12 +107,15 @@ def _query(self, node: Node | None, start: int, end: int, left: int, right: int) if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 210e9a2d6e678af590843ff02cfef113f0d4c3e8 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:57:21 +0530 Subject: [PATCH 19/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 58 +++++++++++++--------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index cf6dbed0dbd9..074e137bb366 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,13 +1,11 @@ from __future__ import annotations - class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None - class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -54,12 +52,22 @@ def update(self, version: int, index: int, value: int) -> int: self.roots.append(new_root) return len(self.roots) - 1 - def _update( - self, node: Node | None, start: int, end: int, index: int, value: int - ) -> Node: - if node is None: - raise ValueError("Cannot update a None node") + def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: + """ + Updates the node for the specified index and value and returns the new node. + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> old_root = pst.roots[0] + >>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5 + >>> new_root.value # New sum after update + 13 + >>> old_root.value # Old root remains unchanged + 10 + >>> new_root.left.value # Updated left child + 6 + >>> new_root.right.value # Right child remains the same + 7 + """ if start == end: return Node(value) @@ -68,14 +76,12 @@ def _update( if index <= mid: new_node.left = self._update(node.left, start, mid, index, value) - new_node.right = node.right + new_node.right = node.right # Ensure right node is the same as the original else: - new_node.left = node.left + new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + ( - new_node.right.value if new_node.right else 0 - ) + new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) return new_node @@ -91,31 +97,35 @@ def query(self, version: int, left: int, right: int) -> int: >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 >>> pst.query(version_1, 0, 3) # Sum of all elements in new version 13 - >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 in new version + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) - def _query( - self, node: Node | None, start: int, end: int, left: int, right: int - ) -> int: - if node is None: - return 0 + def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: + """ + Queries the sum of values in the range [left, right] for the given node. - if left > end or right < start: + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> root = pst.roots[0] + >>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2 + 5 + >>> pst._query(root, 0, 3, 0, 3) # Sum of all elements + 10 + >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3 + 7 + """ + if node is None or left > end or right < start: return 0 if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From fc627f1e5f6c90115b2eb95cc80cc3e3a14e1a13 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:27:42 +0000 Subject: [PATCH 20/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 074e137bb366..05194fa20a4a 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -81,7 +83,9 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) + new_node.value = new_node.left.value + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -97,7 +101,7 @@ def query(self, version: int, left: int, right: int) -> int: >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 >>> pst.query(version_1, 0, 3) # Sum of all elements in new version 13 - >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) @@ -120,12 +124,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 4598bc83a2393ae91844fea91eaef00d19b44dcb Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 16:59:44 +0530 Subject: [PATCH 21/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 05194fa20a4a..fc541976f03e 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,13 +1,11 @@ from __future__ import annotations - class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None - class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -83,9 +81,7 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + ( - new_node.right.value if new_node.right else 0 - ) + new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) return new_node @@ -124,15 +120,12 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 103651e1ce65b4d0539d61b6e513ff9dc1207bcb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:30:05 +0000 Subject: [PATCH 22/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index fc541976f03e..05194fa20a4a 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -81,7 +83,9 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) + new_node.value = new_node.left.value + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -120,12 +124,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From e968d1261b6674eef9ec0bd9f9f0945b6d0dca20 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 17:04:04 +0530 Subject: [PATCH 23/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 71 +++------------------- 1 file changed, 8 insertions(+), 63 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 05194fa20a4a..1cd526a2936c 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,13 +1,11 @@ from __future__ import annotations - class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None - class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -17,15 +15,6 @@ def __init__(self, arr: list[int]) -> None: def _build(self, arr: list[int], start: int, end: int) -> Node: """ Builds a segment tree from the provided array. - - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> root = pst._build([1, 2, 3, 4], 0, 3) - >>> root.value # Sum of the whole array - 10 - >>> root.left.value # Sum of the left half - 3 - >>> root.right.value # Sum of the right half - 7 """ if start == end: return Node(arr[start]) @@ -39,37 +28,18 @@ def _build(self, arr: list[int], start: int, end: int) -> Node: def update(self, version: int, index: int, value: int) -> int: """ Updates the value at the given index and returns the new version. - - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 - >>> pst.query(version_1, 0, 3) # Query sum of all elements in new version - 13 - >>> pst.query(0, 0, 3) # Original version remains unchanged - 10 - >>> version_2 = pst.update(version_1, 3, 6) # Update index 3 to 6 in version_1 - >>> pst.query(version_2, 0, 3) # Query sum of all elements in newest version - 15 """ new_root = self._update(self.roots[version], 0, self.n - 1, index, value) self.roots.append(new_root) return len(self.roots) - 1 - def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: + def _update(self, node: Node | None, start: int, end: int, index: int, value: int) -> Node: """ Updates the node for the specified index and value and returns the new node. - - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> old_root = pst.roots[0] - >>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5 - >>> new_root.value # New sum after update - 13 - >>> old_root.value # Old root remains unchanged - 10 - >>> new_root.left.value # Updated left child - 6 - >>> new_root.right.value # Right child remains the same - 7 """ + if node is None: # Handle the None case + node = Node() # Create a new node if None + if start == end: return Node(value) @@ -83,56 +53,31 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + ( - new_node.right.value if new_node.right else 0 - ) + new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) return new_node def query(self, version: int, left: int, right: int) -> int: """ Queries the sum in the given range for the specified version. - - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> pst.query(0, 0, 3) # Sum of all elements in original version - 10 - >>> pst.query(0, 1, 2) # Sum of elements at index 1 and 2 in original version - 5 - >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 - >>> pst.query(version_1, 0, 3) # Sum of all elements in new version - 13 - >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 - 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) - def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: + def _query(self, node: Node | None, start: int, end: int, left: int, right: int) -> int: """ Queries the sum of values in the range [left, right] for the given node. - - >>> pst = PersistentSegmentTree([1, 2, 3, 4]) - >>> root = pst.roots[0] - >>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2 - 5 - >>> pst._query(root, 0, 3, 0, 3) # Sum of all elements - 10 - >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3 - 7 """ if node is None or left > end or right < start: return 0 if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 4e95c904f0fd5b4bf74bca427241082ac8a74c6b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:34:26 +0000 Subject: [PATCH 24/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 1cd526a2936c..54fa38320b57 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -33,7 +35,9 @@ def update(self, version: int, index: int, value: int) -> int: self.roots.append(new_root) return len(self.roots) - 1 - def _update(self, node: Node | None, start: int, end: int, index: int, value: int) -> Node: + def _update( + self, node: Node | None, start: int, end: int, index: int, value: int + ) -> Node: """ Updates the node for the specified index and value and returns the new node. """ @@ -53,7 +57,9 @@ def _update(self, node: Node | None, start: int, end: int, index: int, value: in new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) + new_node.value = new_node.left.value + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -63,7 +69,9 @@ def query(self, version: int, left: int, right: int) -> int: """ return self._query(self.roots[version], 0, self.n - 1, left, right) - def _query(self, node: Node | None, start: int, end: int, left: int, right: int) -> int: + def _query( + self, node: Node | None, start: int, end: int, left: int, right: int + ) -> int: """ Queries the sum of values in the range [left, right] for the given node. """ @@ -72,12 +80,15 @@ def _query(self, node: Node | None, start: int, end: int, left: int, right: int) if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From 9e07fc9cd4d18127b7988ebb7acb54290529bd45 Mon Sep 17 00:00:00 2001 From: Putul Singh <127419636+putul03@users.noreply.github.com> Date: Sat, 19 Oct 2024 17:07:38 +0530 Subject: [PATCH 25/26] Update persistent_segment_tree.py --- data_structures/persistent_segment_tree.py | 75 ++++++++++++++++------ 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index 54fa38320b57..fc541976f03e 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,13 +1,11 @@ from __future__ import annotations - class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None - class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -17,6 +15,15 @@ def __init__(self, arr: list[int]) -> None: def _build(self, arr: list[int], start: int, end: int) -> Node: """ Builds a segment tree from the provided array. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> root = pst._build([1, 2, 3, 4], 0, 3) + >>> root.value # Sum of the whole array + 10 + >>> root.left.value # Sum of the left half + 3 + >>> root.right.value # Sum of the right half + 7 """ if start == end: return Node(arr[start]) @@ -30,20 +37,37 @@ def _build(self, arr: list[int], start: int, end: int) -> Node: def update(self, version: int, index: int, value: int) -> int: """ Updates the value at the given index and returns the new version. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 + >>> pst.query(version_1, 0, 3) # Query sum of all elements in new version + 13 + >>> pst.query(0, 0, 3) # Original version remains unchanged + 10 + >>> version_2 = pst.update(version_1, 3, 6) # Update index 3 to 6 in version_1 + >>> pst.query(version_2, 0, 3) # Query sum of all elements in newest version + 15 """ new_root = self._update(self.roots[version], 0, self.n - 1, index, value) self.roots.append(new_root) return len(self.roots) - 1 - def _update( - self, node: Node | None, start: int, end: int, index: int, value: int - ) -> Node: + def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node: """ Updates the node for the specified index and value and returns the new node. - """ - if node is None: # Handle the None case - node = Node() # Create a new node if None + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> old_root = pst.roots[0] + >>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5 + >>> new_root.value # New sum after update + 13 + >>> old_root.value # Old root remains unchanged + 10 + >>> new_root.left.value # Updated left child + 6 + >>> new_root.right.value # Right child remains the same + 7 + """ if start == end: return Node(value) @@ -57,38 +81,51 @@ def _update( new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + ( - new_node.right.value if new_node.right else 0 - ) + new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) return new_node def query(self, version: int, left: int, right: int) -> int: """ Queries the sum in the given range for the specified version. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> pst.query(0, 0, 3) # Sum of all elements in original version + 10 + >>> pst.query(0, 1, 2) # Sum of elements at index 1 and 2 in original version + 5 + >>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5 + >>> pst.query(version_1, 0, 3) # Sum of all elements in new version + 13 + >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 + 8 """ return self._query(self.roots[version], 0, self.n - 1, left, right) - def _query( - self, node: Node | None, start: int, end: int, left: int, right: int - ) -> int: + def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int: """ Queries the sum of values in the range [left, right] for the given node. + + >>> pst = PersistentSegmentTree([1, 2, 3, 4]) + >>> root = pst.roots[0] + >>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2 + 5 + >>> pst._query(root, 0, 3, 0, 3) # Sum of all elements + 10 + >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3 + 7 """ if node is None or left > end or right < start: return 0 if left <= start and right >= end: return node.value mid = (start + end) // 2 - return self._query(node.left, start, mid, left, right) + self._query( - node.right, mid + 1, end, left, right - ) - + return (self._query(node.left, start, mid, left, right) + + self._query(node.right, mid + 1, end, left, right)) # Running the doctests if __name__ == "__main__": import doctest - print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.") From bcd9f5dcdd1a8e8067172fb981672b2b13396879 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:37:59 +0000 Subject: [PATCH 26/26] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/persistent_segment_tree.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/data_structures/persistent_segment_tree.py b/data_structures/persistent_segment_tree.py index fc541976f03e..05194fa20a4a 100644 --- a/data_structures/persistent_segment_tree.py +++ b/data_structures/persistent_segment_tree.py @@ -1,11 +1,13 @@ from __future__ import annotations + class Node: def __init__(self, value: int = 0) -> None: self.value: int = value self.left: Node | None = None self.right: Node | None = None + class PersistentSegmentTree: def __init__(self, arr: list[int]) -> None: self.n: int = len(arr) @@ -81,7 +83,9 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N new_node.left = node.left # Ensure left node is the same as the original new_node.right = self._update(node.right, mid + 1, end, index, value) - new_node.value = new_node.left.value + (new_node.right.value if new_node.right else 0) + new_node.value = new_node.left.value + ( + new_node.right.value if new_node.right else 0 + ) return new_node @@ -120,12 +124,15 @@ def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int if left <= start and right >= end: return node.value mid = (start + end) // 2 - return (self._query(node.left, start, mid, left, right) + - self._query(node.right, mid + 1, end, left, right)) + return self._query(node.left, start, mid, left, right) + self._query( + node.right, mid + 1, end, left, right + ) + # Running the doctests if __name__ == "__main__": import doctest + print("Running doctests...") result = doctest.testmod() print(f"Ran {result.attempted} tests, {result.failed} failed.")