• [Leetcode]307. Range Sum Query


    这是Leetcode第307题,给一个数组,然后求指定下标之间的数之和,已知数组中的值可以更新,并且更新和求和操作会被频繁调用。
    这是一道线段树的基础题,线段树是一种二叉搜索树。它将一段区间划分为若干单位区间,每一个节点都储存着一个区间。它功能强大,支持区间求和,区间最大值,区间修改,单点修改等操作。
    线段树的思想和分治思想很相像。线段树的每一个节点都储存着一段区间[L…R]的信息,其中叶子节点L=R。它的大致思想是:将一段大区间平均地划分成2个小区间,每一个小区间都再平均分成2个更小区间……以此类推,直到每一个区间的L等于R(这样这个区间仅包含一个节点的信息,无法被划分)。通过对这些区间进行修改、查询,来实现对大区间的修改、查询。
    这样一来,每一次修改、查询的时间复杂度都只为(O(log_2n))

    注意,可以用线段树维护的问题必须满足区间加法,否则是不可能将大问题划分成子问题来解决的。

    通过这道题,也可以写一个线段树的模板,如下:

    #Segment tree node
    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):
            """
            initialize your data structure here.
            :type nums: List[int]
            """
            #helper function to create the tree from input array
            def createTree(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)
    
                #recursively build the Segment tree
                root.left = createTree(nums, l, mid)
                root.right = createTree(nums, mid+1, r)
    
                #Total stores the sum of all leaves under root
                #i.e. those elements lying between (start, end)
                root.total = root.left.total + root.right.total
    
                return root
    
            self.root = createTree(nums, 0, len(nums)-1)
    
        def update(self, i, val):
            """
            :type i: int
            :type val: int
            :rtype: int
            """
            #Helper function to update a value
            def updateVal(root, i, val):
    
                #Base case. The actual value will be updated in a leaf.
                #The total is then propogated upwards
                if root.start == root.end:
                    root.total = val
                    return val
    
                mid = (root.start + root.end) // 2
    
                #If the index is less than the mid, that leaf must be in the left subtree
                if i <= mid:
                    updateVal(root.left, i, val)
    
                #Otherwise, the right subtree
                else:
                    updateVal(root.right, i, val)
    
                #Propogate the changes after recursive call returns
                root.total = root.left.total + root.right.total
    
                return root.total
    
            return updateVal(self.root, i, val)
    
        def sumRange(self, i, j):
            """
            sum of elements nums[i..j], inclusive.
            :type i: int
            :type j: int
            :rtype: int
            """
            #Helper function to calculate range sum
            def rangeSum(root, i, j):
    
                #If the range exactly matches the root, we already have the sum
                if root.start == i and root.end == j:
                    return root.total
    
                mid = (root.start + root.end) // 2
    
                #If end of the range is less than the mid, the entire interval lies
                #in the left subtree
                if j <= mid:
                    return rangeSum(root.left, i, j)
    
                #If start of the interval is greater than mid, the entire inteval lies
                #in the right subtree
                elif i >= mid + 1:
                    return rangeSum(root.right, i, j)
    
                #Otherwise, the interval is split. So we calculate the sum recursively,
                #by splitting the interval
                else:
                    return rangeSum(root.left, i, mid) + rangeSum(root.right, mid+1, j)
    
            return rangeSum(self.root, i, j)
    

    参考:
    线段树详解

  • 相关阅读:
    1CSS与文档
    14交互活动:XHTML表单
    13开始制作表格:表格和列表
    12布置元素:布局和排版
    11高级网站构建:div和span
    10与元素亲密接触:盒元素(the box model)
    tp5.1 与vue ajax请求跨域的问题
    小程序父子组件互相传参,互相调用方法
    PHP/js数组与字符串的操作,字符串转数组,数组转字符串,去掉字符串最后一个字符,判断二维数组是否为空等
    easyui datagrid分页栏位置问题
  • 原文地址:https://www.cnblogs.com/hellojamest/p/11624447.html
Copyright © 2020-2023  润新知