Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b344185

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

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed
Lines changed: 88 additions & 0 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /