什么是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上的应用