• Segment Tree, 线段树


    什么是Segment Tree?

    它是一个binary tree,表示每个parent只有两个children;他是平衡的(balanced binary tree),但不定是完美平衡,保证是O(logn)的高度。

    它的每个叶子结点代表了数组里的每一个元素,并且还带有一个范围:start,end,如(0,1),表示数组的元素的第0和第1个。

    每个非叶子结点,就是left,right两个children的值的和,同时也带有一个范围,start是left的start,end是right的end。

    Segment Tree提供的操作

    • build(start,end,values),时间复杂度为O(n)
    • update(index,value),时间复杂度为O(logn)
    • rangeQuery(start,end),时间复杂度为O(logn+k),k值是会复盖到节点的数量

    它的作用是什么?

    Segment Tree与树状数组(Binary indexed tree)相似,也用来处理数组相应的区间查询(range queue)和元素更新(update)操作。与树状数组不同的是,线段树不止可以适用于区间求和的查询,也可以进行区间最大值,区间最小值 或者 区间异或值的查询。

    代码实现

    TreeNode

    class TreeNode constructor(start: Int, end: Int, sum: Int = 0) {
        var start = 0
        var end = 0
        var sum = 0
        var left:TreeNode?=null
        var right:TreeNode?=null
    
        init {
            this.start = start
            this.end = end
            this.sum = sum
        }
    }

    SegmentTree

    class SegmentTree {
    
        fun build(nums: IntArray?, start: Int, end: Int): TreeNode? {
            if (nums == null) {
                return null
            }
            if (start == end) {
                return TreeNode(start, end, nums!![start])
            }
            val currentNode = TreeNode(start, end)
            val mid = (start + end) / 2
            currentNode.left = build(nums, start, mid)
            currentNode.right = build(nums, mid + 1, end)
            val leftSum = currentNode.left?.sum ?: 0
            val rightSum = currentNode.right?.sum ?: 0
            currentNode.sum = leftSum + rightSum
            return currentNode
        }
    
        fun update(node: TreeNode?, i: Int, value: Int) {
            if (node == null) {
                return
            }
            if (node.start == i && node.end == i) {
                node.sum = value
                return
            }
            val mid = (node.start + node.end) / 2
            if (i <= mid) {
                update(node.left, i, value)
            } else {
                update(node.right, i, value)
            }
            val leftSum = node.left?.sum ?: 0
            val rightSum = node.right?.sum ?: 0
            node.sum = leftSum + rightSum
        }
    
        fun rangeQueue(node: TreeNode?, i: Int, j: Int): Int {
            if (node == null) {
                return 0
            }
            if (i == node.start && j == node.end) {
                return node.sum
            }
            val mid = (node.start + node.end) / 2
            if (j<= mid) {
                return rangeQueue(node.left, i, j)
            } else if (i > mid) {
                return rangeQueue(node.right, i, j)
            } else {
                return rangeQueue(node.left, i, mid) + rangeQueue(node.right, mid + 1, j)
            }
        }
    }

    Leetcode上的应用

    307. Range Sum Query - Mutable

  • 相关阅读:
    linux下ssh端口的修改和登录
    linux找回密码
    XAMPP命令之LAMPP
    VirtualBox 复制vdi文件和修改vdi的uuid
    探讨PHP页面跳转几种实现技巧
    CSS盒模型和margin重叠
    8--数组旋转
    9--斐波那契数列
    7--动态规划
    6--树的遍历
  • 原文地址:https://www.cnblogs.com/johnnyzhao/p/12544561.html
Copyright © 2020-2023  润新知