题目地址:
https://www.lintcode.com/problem/segment-tree-query-ii/description
对于一个数组,建一棵线段树,存储这个数组在某个区间 [ x s , x e ] [x_s,x_e] [xs,xe]的元素个数(假设这个数组的范围都含在这个区间里了)。再给定一个区间 [ a , b ] [a,b] [a,b],问该数组在这个区间有多少个数。
思路是分治法。设树根维护的是
[
x
s
,
x
e
]
[x_s,x_e]
[xs,xe],区间中点是
m
=
x
s
+
x
e
2
m=\frac{x_s+x_e}{2}
m=2xs+xe,要求的区间是
[
a
,
b
]
[a,b]
[a,b]。分下面几个情况讨论:
1、两个区间没有交集,则返回
0
0
0;
2、
a
≤
x
s
,
b
≥
x
e
a\le x_s,b\ge x_e
a≤xs,b≥xe,那么直接返回树根维护的个数即可;
2、
a
≤
b
≤
m
a\le b\le m
a≤b≤m,那么就要到左子树里找
[
a
,
b
]
[a,b]
[a,b]的个数;
3、
b
≥
a
≥
m
+
1
b\ge a\ge m+1
b≥a≥m+1,那么就要到右子树里找
[
a
,
b
]
[a,b]
[a,b]的个数;
4、
a
≤
m
<
b
a\le m<b
a≤m<b,那么就要左右子树里都要找,在左子树里找
[
a
,
m
]
[a,m]
[a,m]的个数,在右子树里找
[
m
+
1
,
b
]
[m+1,b]
[m+1,b]的个数,然后结合起来就得到了
[
a
,
b
]
[a,b]
[a,b]的个数。
上述四种情况都可以用递归来解决。代码如下:
public class Solution {
/*
* @param root: The root of segment tree.
* @param start: start value.
* @param end: end value.
* @return: The count number in the interval [start, end]
*/
public int query(SegmentTreeNode root, int start, int end) {
// write your code here
if (root == null || end < root.start || start > root.end) {
return 0;
}
if (start <= root.start && end >= root.end) {
return root.count;
}
int mid = root.start + (root.end - root.start >> 1);
if (end <= mid) {
return query(root.left, start, end);
}
if (mid < start) {
return query(root.right, start, end);
}
return query(root.left, start, mid) + query(root.right, mid + 1, end);
}
}
class SegmentTreeNode {
int start, end, count;
SegmentTreeNode left, right;
public SegmentTreeNode(int start, int end, int count) {
this.start = start;
this.end = end;
this.count = count;
}
}
时间复杂度 O ( log ( b − a ) ) O(\log (b-a)) O(log(b−a)),空间 O ( log ( x e − x s ) ) O(\log (x_e-x_s)) O(log(xe−xs))(可以参考https://blog.csdn.net/qq_46105170/article/details/108414631)。