线段树(Segment Tree)又叫区间树(Interval Tree),它实际上是一颗二叉树,树种的每一个节点表示一个区间[a, b],左儿子的区间是[a, (a+b)/2],右儿子的区间是[(a+b)/2+1, b]。
线段树常用于区间统计/查询相关的问题:比如某些数据可以按区间进行划分,按区间动态进行修改,而且还需要按区间多次进行查询,那么使用线段树可以达到较快查询速度。动态的求/更新区间和、区间最值就适用于用线段树来求解。
由于线段树的深度不会超过logL,所以查询的时间复杂度也是O(logL)。
北大的POJ上有关于这个高级数据结构的介绍:http://poj.org/summerschool/1_interval_tree.pdf
LintCode上线段树专题下有这些题目:
创建线段树,利用递归的方式:
/**
* Definition of SegmentTreeNode:
* public class SegmentTreeNode {
* public int start, end;
* public SegmentTreeNode left, right;
* public SegmentTreeNode(int start, int end) {
* this.start = start, this.end = end;
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/**
*@param start, end: Denote an segment / interval
*@return: The root of Segment Tree
*/
public SegmentTreeNode build(int start, int end) {
if (start <= end) {
SegmentTreeNode node = new SegmentTreeNode(start, end);
if (start == end) {
return node;
}
node.left = build(start, (start + end) / 2);
node.right = build( (start + end) / 2 + 1, end);
return node;
}
return null;
}
}
439. Segment Tree Build II
跟上题类似,多了一个要求,需要每个节点还要保存最大值的信息。
/**
* Definition of SegmentTreeNode:
* public class SegmentTreeNode {
* public int start, end, max;
* public SegmentTreeNode left, right;
* public SegmentTreeNode(int start, int end, int max) {
* this.start = start;
* this.end = end;
* this.max = max
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/**
*@param A: a list of integer
*@return: The root of Segment Tree
*/
public SegmentTreeNode buildHelper(int[] A, int start, int end) {
if (start <= end) {
SegmentTreeNode node = new SegmentTreeNode(start, end, A[start]);
if (start == end) {
return node;
}
node.left = buildHelper(A, start, (start + end) / 2);
node.right = buildHelper(A, (start + end) / 2 + 1, end);
node.max = Math.max(node.left.max, node.right.max);
return node;
}
return null;
}
public SegmentTreeNode build(int[] A) {
return buildHelper(A, 0, A.length - 1);
}
}
对线段树进行查询,要求找到给定区间(start, end)内的最大值
/**
* Definition of SegmentTreeNode:
* public class SegmentTreeNode {
* public int start, end, max;
* public SegmentTreeNode left, right;
* public SegmentTreeNode(int start, int end, int max) {
* this.start = start;
* this.end = end;
* this.max = max
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/**
*@param root, start, end: The root of segment tree and
* an segment / interval
*@return: The maximum number in the interval [start, end]
*/
public int query(SegmentTreeNode root, int start, int end) {
// 查询区间在当前节点的范围之内
if (start <= root.start && root.end <= end) {
return root.max;
}
int mid = (root.start + root.end) / 2;
int ans = Integer.MIN_VALUE;
// 查询区间和左子树有交集
if (start <= mid) {
ans = Math.max(ans, query(root.left, start, end));
}
// 查询区间和右子树有交集
if (end >= mid + 1) {
ans = Math.max(ans, query(root.right, start, end));
}
return ans;
}
}
<