For an array, we can build a SegmentTree
for it, each node stores an extra attribute count
to denote the number of elements in the the array which value is between interval start and end. (The array may not fully filled by elements)
Design a query
method with three parameters root
, start
and end
, find the number of elements in the in array's interval [start, end] by the given root of value SegmentTree.
Notice
It is much easier to understand this problem if you finished Segment Tree Buildand Segment Tree Query first.
For array [0, 2, 3]
, the corresponding value Segment Tree is:
[0, 3, count=3]
/ \
[0,1,count=1] [2,3,count=2]
/ \ / \
[0,0,count=1] [1,1,count=0] [2,2,count=1], [3,3,count=1]
query(1, 1)
, return 0
query(1, 2)
, return 1
query(2, 3)
, return 2
query(0, 2)
, return 2
依旧是一道二分题。这次start end指的并不是index了而是数组的zhi的取值范围,count表示的是在这个取值范围之内有几个数字。
同样也是采用二分法。
如果root.start >= start && root.end <= end, 这就意味着这个root所包含的范围是我们要求解的一个范围的子范围,这个范围内的count值我们是要的,所以直接返回root。count
接下来进行二分。
mid = (start + end)/2;
如果mid 《start, 说明root节点的左半部分是不需要考虑的,因此调用 query(root.right, start, end);
如果 mid 》= end, 说明root节点的右侧的值全部比end要大,也不是我们需要考虑的范围,因此调用 query(root,left, start ,end)
最后,如果mid在start跟end之间,那么就需要分别统计 start~mid mid+1~ end范围的结果,然后加起来。
代码:
public int query(SegmentTreeNode root, int start, int end) {
// write your code here
if(root == null || start > end) return 0;
if(root.start >= start && root.end <= end){
return root.count;
}
int mid = (root.start + root.end)/2;
if(mid < start){
return query(root.right, start, end);
}
if(mid >= end){
return query(root.left, start, end);
}
return query(root.left, start, mid) + query(root.right, mid+1, end);
}