Skip to content

Commit 01ee53a

Browse files
authored
Add comments, change variable names
1 parent 6be290c commit 01ee53a

File tree

1 file changed

+55
-37
lines changed

1 file changed

+55
-37
lines changed

Diff for: data_structures/arrays/sparse_table.py

+55-37
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""
22
Sparse table is a data structure that allows answering range queries on
3-
a static array, i.e. the elements do not change throughout all the queries.
3+
a static number_listay, i.e. the elements do not change throughout all the queries.
44
55
The implementation below will solve the problem of Range Minimum Query:
6-
Finding the minimum value of a subset [L..R] of a static array.
6+
Finding the minimum value of a subset [L..R] of a static number_listay.
77
88
Overall time complexity: O(nlogn)
99
Overall space complexity: O(nlogn)
@@ -12,80 +12,98 @@
1212
"""
1313

1414

15-
def build_sparse_table(arr: list[int], arr_length: int) -> list[list[int]]:
15+
def build_sparse_table(number_list: list[int]) -> list[list[int]]:
1616
"""
17-
Precompute range minimum queries with power of two length
18-
and store the precomputed values in a table.
19-
20-
>>> build_sparse_table([8, 1, 0, 3, 4, 9, 3], 7)
17+
Precompute range minimum queries with power of two length and store the precomputed
18+
values in a table.
19+
20+
>>> build_sparse_table([8, 1, 0, 3, 4, 9, 3])
2121
[[8, 1, 0, 3, 4, 9, 3], [1, 0, 0, 3, 4, 3, 0], [0, 0, 0, 3, 0, 0, 0]]
22-
>>> build_sparse_table([3, 1, 9], 3)
22+
>>> build_sparse_table([3, 1, 9])
2323
[[3, 1, 9], [1, 1, 0]]
24-
>>> build_sparse_table([], 0)
24+
>>> build_sparse_table([])
2525
Traceback (most recent call last):
2626
...
27-
ValueError: math domain error
27+
ValueError: empty number list not allowed
2828
"""
2929
import math
3030

31-
if arr == []:
32-
raise ValueError("math domain error")
31+
if number_list == []:
32+
raise ValueError("empty number list not allowed")
33+
34+
length = len(number_list)
35+
"""
36+
Initialise sparse_table
37+
38+
sparse_table[j][i] represents the minimum value of
39+
the subset of length (2 ** j) of number_list, starting from index i.
40+
"""
3341

34-
# Initialise lookup table
35-
k = int(math.log2(arr_length)) + 1
36-
lookup = [[0 for i in range(arr_length)] for j in range(k)]
42+
# smallest power of 2 subset length that fully covers number_list
43+
row = int(math.log2(length)) + 1
44+
sparse_table = [[0 for i in range(length)] for j in range(row)]
3745

38-
for i in range(arr_length):
39-
lookup[0][i] = arr[i]
46+
# minimum of subset of length 1 is that value itself
47+
for i, value in enumerate(number_list):
48+
sparse_table[0][i] = value
4049

4150
j = 1
4251

43-
while (1 << j) <= arr_length:
44-
# Compute the minimum value for all intervals with size (2 ** j)
52+
# compute the minimum value for all intervals with size (2 ** j)
53+
while (1 << j) <= length:
4554
i = 0
46-
while (i + (1 << j) - 1) < arr_length:
47-
lookup[j][i] = min(lookup[j - 1][i + (1 << (j - 1))], lookup[j - 1][i])
55+
# while subset starting from i still have at least (2 ** j) elements
56+
while (i + (1 << j) - 1) < length:
57+
# split range [i, i + 2 ** j] and find minimum of 2 halves
58+
sparse_table[j][i] = min(
59+
sparse_table[j - 1][i + (1 << (j - 1))],
60+
sparse_table[j - 1][i]
61+
)
62+
4863
i += 1
4964

5065
j += 1
5166

52-
return lookup
67+
return sparse_table
5368

5469

55-
def query(lookup: list[list[int]], left_bound: int, right_bound: int) -> int:
70+
def query(sparse_table: list[list[int]], left_bound: int, right_bound: int) -> int:
5671
"""
57-
>>> query(build_sparse_table([8, 1, 0, 3, 4, 9, 3], 7), 0, 4)
72+
>>> query(build_sparse_table([8, 1, 0, 3, 4, 9, 3]), 0, 4)
5873
0
59-
>>> query(build_sparse_table([8, 1, 0, 3, 4, 9, 3], 7), 4, 6)
74+
>>> query(build_sparse_table([8, 1, 0, 3, 4, 9, 3]), 4, 6)
6075
3
61-
>>> query(build_sparse_table([8, 1, 0, 3, 4, 9, 3], 7), 0, 11)
76+
>>> query(build_sparse_table([8, 1, 0, 3, 4, 9, 3]), 0, 11)
6277
Traceback (most recent call last):
6378
...
6479
IndexError: list index out of range
6580
66-
>>> query(build_sparse_table([3, 1, 9], 3), 2, 2)
81+
>>> query(build_sparse_table([3, 1, 9]), 2, 2)
6782
9
68-
>>> query(build_sparse_table([3, 1, 9], 3), 0, 1)
83+
>>> query(build_sparse_table([3, 1, 9]), 0, 1)
6984
1
7085
71-
>>> query(build_sparse_table([], 0), 0, 0)
86+
>>> query(build_sparse_table([]), 0, 0)
7287
Traceback (most recent call last):
7388
...
74-
ValueError: math domain error
89+
ValueError: empty number list not allowed
7590
"""
7691
import math
7792

78-
if lookup == []:
79-
raise ValueError("math domain error")
80-
if left_bound < 0 or right_bound >= len(lookup[0]):
93+
if left_bound < 0 or right_bound >= len(sparse_table[0]):
8194
raise IndexError("list index out of range")
8295

96+
# highest subset length of power of 2 that is within range [left_bound, right_bound]
97+
j = int(math.log2(right_bound - left_bound + 1))
98+
8399
"""
84-
Find the highest power of 2
85-
that is at least the number of elements in a given range.
100+
minimum of 2 overlapping smaller subsets: [left_bound, left_bound + 2 ** j - 1]
101+
and [right_bound - 2 ** j + 1, right_bound]
86102
"""
87-
j = int(math.log2(right_bound - left_bound + 1))
88-
return min(lookup[j][right_bound - (1 << j) + 1], lookup[j][left_bound])
103+
return min(
104+
sparse_table[j][right_bound - (1 << j) + 1],
105+
sparse_table[j][left_bound]
106+
)
89107

90108

91109
if __name__ == "__main__":

0 commit comments

Comments
 (0)