Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions data_structures/persistent_segment_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
class Node:
def __init__(self, value=0):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __init__. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: value

"""
Initialize a segment tree node.

Args:
value (int): The value of the node.
"""
self.value = value
self.left = None
self.right = None


class PersistentSegmentTree:
def __init__(self, arr):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __init__. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: arr

"""
Initialize the persistent segment tree with the given array.

Args:
arr (list): The initial array to build the segment tree.
"""
self.n = len(arr)
self.roots = []
self.roots.append(self._build(arr, 0, self.n - 1))

def _build(self, arr, start, end):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: _build. If the function does not return a value, please provide the type hint as: def function() -> None:

As there is no test file in this pull request nor any test function or class in the file data_structures/persistent_segment_tree.py, please provide doctest for the function _build

Please provide type hint for the parameter: arr

Please provide type hint for the parameter: start

Please provide type hint for the parameter: end

"""
Recursively build the segment tree.

Args:
arr (list): The input array.
start (int): The starting index of the segment.
end (int): The ending index of the segment.

Returns:
Node: The root node of the segment tree for the current segment.
"""
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, index, value):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: update. If the function does not return a value, please provide the type hint as: def function() -> None:

As there is no test file in this pull request nor any test function or class in the file data_structures/persistent_segment_tree.py, please provide doctest for the function update

Please provide type hint for the parameter: version

Please provide type hint for the parameter: index

Please provide type hint for the parameter: value

"""
Update the value at the specified index in the specified version.

Args:
version (int): The version of the segment tree to update.
index (int): The index to update.
value (int): The new value to set at the index.

Returns:
int: The index of the new version of the root node.
"""
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, start, end, index, value):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: _update. If the function does not return a value, please provide the type hint as: def function() -> None:

As there is no test file in this pull request nor any test function or class in the file data_structures/persistent_segment_tree.py, please provide doctest for the function _update

Please provide type hint for the parameter: node

Please provide type hint for the parameter: start

Please provide type hint for the parameter: end

Please provide type hint for the parameter: index

Please provide type hint for the parameter: value

"""
Recursively update the segment tree.

Args:
node (Node): The current node of the segment tree.
start (int): The starting index of the segment.
end (int): The ending index of the segment.
index (int): The index to update.
value (int): The new value to set at the index.

Returns:
Node: The new root node after the update.
"""
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, left, right):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: query. If the function does not return a value, please provide the type hint as: def function() -> None:

As there is no test file in this pull request nor any test function or class in the file data_structures/persistent_segment_tree.py, please provide doctest for the function query

Please provide type hint for the parameter: version

Please provide type hint for the parameter: left

Please provide type hint for the parameter: right

"""
Query the sum of values in the range [left, right] for the specified version.

Args:
version (int): The version of the segment tree to query.
left (int): The left index of the range.
right (int): The right index of the range.

Returns:
int: The sum of the values in the specified range.
"""
return self._query(self.roots[version], 0, self.n - 1, left, right)

def _query(self, node, start, end, left, right):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: _query. If the function does not return a value, please provide the type hint as: def function() -> None:

As there is no test file in this pull request nor any test function or class in the file data_structures/persistent_segment_tree.py, please provide doctest for the function _query

Please provide type hint for the parameter: node

Please provide type hint for the parameter: start

Please provide type hint for the parameter: end

Please provide type hint for the parameter: left

Please provide type hint for the parameter: right

"""
Recursively query the segment tree.

Args:
node (Node): The current node of the segment tree.
start (int): The starting index of the segment.
end (int): The ending index of the segment.
left (int): The left index of the range.
right (int): The right index of the range.

Returns:
int: The sum of the values in the specified range.
"""
if right < start or end < left:
return 0 # out of range

if left <= start and end <= right:
return node.value # completely within range

mid = (start + end) // 2
sum_left = self._query(node.left, start, mid, left, right)
sum_right = self._query(node.right, mid + 1, end, left, right)
return sum_left + sum_right


# Example usage and doctests
if __name__ == "__main__":
import doctest

Check failure on line 136 in data_structures/persistent_segment_tree.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

data_structures/persistent_segment_tree.py:136:12: F401 `doctest` imported but unused

# Creating an initial array
arr = [1, 2, 3, 4, 5]
pst = PersistentSegmentTree(arr)

# Querying the initial version
assert pst.query(0, 0, 4) == 15 # sum of [1, 2, 3, 4, 5]

# Updating index 2 to value 10 in version 0
new_version = pst.update(0, 2, 10)

# Querying the updated version
assert pst.query(new_version, 0, 4) == 22 # sum of [1, 2, 10, 4, 5]
assert pst.query(0, 0, 4) == 15 # original version unchanged

62 changes: 62 additions & 0 deletions divide_and_conquer/suffix_array_lcp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3

def build_suffix_array(s: str) -> list[int]:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file divide_and_conquer/suffix_array_lcp.py, please provide doctest for the function build_suffix_array

Please provide descriptive name for the parameter: s

"""
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]:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file divide_and_conquer/suffix_array_lcp.py, please provide doctest for the function build_lcp_array

Please provide descriptive name for the parameter: s

"""
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]}")

Check failure on line 62 in divide_and_conquer/suffix_array_lcp.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

divide_and_conquer/suffix_array_lcp.py:62:89: E501 Line too long (96 > 88)
Loading