Leetcode Tag Search | Back

307. Range Sum Query - Mutable

Category: /leetcode

Leetcode Link | Tree template

Given an integer array nums, handle multiple queries of the following types:

  • Update the value of an element in nums.
  • Calculate the sum of the elements of nums between indices left and right inclusive where left <= right.

Implement the NumArray class:

  • NumArray(int[] nums) Initializes the object with the integer array nums.
  • void update(int index, int val) Updates the value of nums[index] to be val.
  • int sumRange(int left, int right) Returns the sum of the elements of nums between indices left and right inclusive (i.e. nums[left] + nums[left + 1] + … + nums[right]).
Example 1:

Input
["NumArray", "sumRange", "update", "sumRange"]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
Output
[null, 9, null, 8]

Explanation
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // return 1 + 3 + 5 = 9
numArray.update(1, 2);   // nums = [1, 2, 5]
numArray.sumRange(0, 2); // return 1 + 2 + 5 = 8
 

Constraints:

1 <= nums.length <= 3 * 104
-100 <= nums[i] <= 100
0 <= index < nums.length
-100 <= val <= 100
0 <= left <= right < nums.length
At most 3 * 104 calls will be made to update and sumRange.

Solution

Segment tree is a very flexible data structure, because it is used to solve numerous range query problems like finding minimum, maximum, sum, greatest common divisor, least common denominator in array in logarithmic time.

The idea here is to build a segment tree. Each node stores the left and right endpoint of an interval and the sum of that interval. All of the leaves will store elements of the array and each internal node will store sum of leaves under it. Creating the tree takes O(n) time. Query and updates are both O(log n).

Time: O(logN)


class Node(object):
  def __init__(self, start, end):
    self.start = start
    self.end = end
    self.total = 0
    self.left = None
    self.right = None

class NumArray(object):
  def __init__(self, nums):
    def build_tree(nums, l, r):
      # base case
      if l > r: return None
      # leaf node
      if l == r:
        n = Node(l, r)
        n.total = nums[l]
        return n
      mid = (l + r) // 2
      root = Node(l, r)
      root.left = build_tree(l, mid)
      root.right = build_tree(mid + 1, r)
      root.total = root.left.total + root.right.total
      return root

    self.root = build_tree(nums, 0, len(nums) - 1)

  def update(self, i, val):
    def update_val(root, i, val):
      # base case, update a leaf, then update upward
      if root.start == root.end:
        root.total = val
        return val
      
      mid = (root.start + root.end) // 2
      if i <= mid:
        update_val(root.left, i, val)
      else:
        update_val(root.right, i, val)
      
      root.total = root.left.total + root.right.total
      return root.total
    return update_val(self.root, i, val)

  def sumRange(self, i, j):
    def sum_range(root, i, j):
      if root.start == i and root.end == j:
        return root.total
      mid = (root.left + root.right) // 2
      if j <= mid:
        return sum_range(root.left, i, j)
      elif i > mid:
        return sum_range(root.right, i, j)
      else:
        return sum_range(root.left, i, mid) + sum_range(root.right, mid + 1, j)
    return sum_range(self.root, i, j)

讨论

提示

  • 如果看不到讨论部分, 请暂时关掉adblock in Firefox/Chrome
  • 本网站使用Javascript实现评论功能, 此处外链对提高您的网站PR没有帮助. (潜台词: 请不要灌水, 谢谢)