区间树
问题描述1:
假如有四个线段 { 1, 2 }, { 2, 4 }, { 1, 3 }, { 4, 9 } ,问线段(3, 4)与这些线段中有几个是重叠的?
分析:按照正常思路是先遍历,依次比对左端点3是否在某个线段中,右端点是否在某个线段中, 如果只有四个线段的话这个是推荐的。但是一旦数据量大了复杂度就高,这时我们需要利用二分查找的思想来判断。
我们先构造一个树,使得只需要判断根节点就知道需不需要搜寻子节点了。比如某个子树最右边是2,那么3,4肯定不会与这些子树下面的线段冲突,这就大大减少了需要查找的数据量。
算法思路:
- 构造二叉排序树,以线段左端点作为排序条件。每添加一个节点更新各子树可到的最右端距离
- 计算重合:如果目标线段左端点大于当前节点子树可到的最大右端点则返回0.如果目标线段与当前节点线段重合则重合数+1,交给左右节点去计算重合的数量。最终的重合数量是左右节点重合数量之和加当前节点是否与目标节点重合
具体代码
public class LineSegmentTree {
public int begin;
public int end;
public int max_right;
LineSegmentTree left;
LineSegmentTree right;
public LineSegmentTree(int begin, int end) {
this.begin = begin;
this.end = end;
//一开始只有一个节点,因此自己作为根节点子树可到的最右端是自己的右端点
max_right = end;
}
private void add(LineSegmentTree child) {
if (child.begin < begin) {
if (left == null)
left = child;
else
left.add(child);
} else {
if (right == null)
right = child;
else
right.add(child);
}
//更新当前节点为根节点的子树可到的最右端距离
if (left != null && left.max_right > max_right)
max_right = left.max_right;
if (right != null && right.max_right > max_right)
max_right = right.max_right;
}
public int getCollisionNum(int tbegin, int tend) {
//如果目标节点起始点比当前子树可到最右端还要大