Skip to content

Commit b344185

Browse files
committed
Added question 307.
1 parent 95d511b commit b344185

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

Diff for: leetcode/medium/307_range_sum_query_mutable.md

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# 307. Range Sum Query - Mutable
2+
3+
## Segment Tree Solution
4+
- Run-time: create_tree() is O(N), sumRange() is O(logN), update() is O(logN)
5+
- Space: O(N)
6+
- N = Number of given nums
7+
8+
A segment tree is similar to a binary tree, in fact, the only difference is that segment trees traversal via. the range of indexes.
9+
Each node of the tree, instead of storing a value, stores the values between the range of indexes.
10+
Segment trees are good if you have a lot of numbers and need to either find the max, min, sum, etc... of a given range.
11+
12+
Naive methods would require O(N) time traversal to find the result of a given range.
13+
Other methods use a 2d array of O(N^2) space and O(N^2) run-time to pre-process every range but O(1) look up after.
14+
These methods don't work well when there are billions of numbers, therefore, segment trees are a great alternative.
15+
16+
```
17+
class NumArray:
18+
19+
def __init__(self, nums: List[int]):
20+
self.tree = SegmentTree(nums)
21+
22+
def update(self, i: int, val: int) -> None:
23+
self.tree.update(i, val)
24+
25+
def sumRange(self, i: int, j: int) -> int:
26+
return self.tree.get_range(i, j)
27+
28+
class SegmentTree(object):
29+
30+
def __init__(self, nums):
31+
self.root = self._create_tree(nums)
32+
33+
def _create_tree(self, nums):
34+
35+
def tree_builder(left, right):
36+
if left > right:
37+
return None
38+
if left == right:
39+
return Node(nums[left], left, right)
40+
mid_idx = (left + right) // 2
41+
left_node = tree_builder(left, mid_idx)
42+
right_node = tree_builder(mid_idx + 1, right)
43+
total_sum = left_node.sum if left_node is not None else 0
44+
total_sum += right_node.sum if right_node is not None else 0
45+
new_node = Node(total_sum, start=left, end=right, left=left_node, right=right_node)
46+
return new_node
47+
48+
return tree_builder(0, len(nums) - 1)
49+
50+
def update(self, idx, val):
51+
52+
def update_helper(curr):
53+
if curr.start_idx == curr.end_idx == idx: # leaf
54+
curr.sum = val
55+
return
56+
mid_idx = (curr.start_idx + curr.end_idx) // 2
57+
if idx <= mid_idx: # go left
58+
update_helper(curr.left)
59+
else: # go right
60+
update_helper(curr.right)
61+
curr.sum = curr.left.sum + curr.right.sum
62+
63+
update_helper(self.root)
64+
65+
def get_range(self, l, r):
66+
67+
def sum_helper(curr, left, right):
68+
if left == curr.start_idx and right == curr.end_idx: # total overlap
69+
return curr.sum
70+
mid_idx = (curr.start_idx + curr.end_idx) // 2
71+
if right <= mid_idx: # range is only on the left subtree?
72+
return sum_helper(curr.left, left, right)
73+
elif left >= mid_idx + 1: # range is only on the right subtree?
74+
return sum_helper(curr.right, left, right)
75+
# ranges are in both left and right subtrees
76+
return sum_helper(curr.left, left, mid_idx) + sum_helper(curr.right, mid_idx + 1, right)
77+
78+
return sum_helper(self.root, l, r)
79+
80+
class Node(object):
81+
82+
def __init__(self, _sum, start, end, left=None, right=None):
83+
self.start_idx = start
84+
self.end_idx = end
85+
self.sum = _sum
86+
self.left = left
87+
self.right = right
88+
```

0 commit comments

Comments
 (0)