lintcode---线段树查询||(区间元素个数)
对于一个数组,我们可以对其建立一棵 线段树
, 每个结点存储一个额外的值 count
来代表这个结点所指代的数组区间内的元素个数. (数组中并不一定每个位置上都有元素)
实现一个 query
的方法,该方法接受三个参数 root
, start
和 end
, 分别代表线段树的根节点和需要查询的区间,找到数组中在区间[start, end]内的元素个数。
注意事项
It is much easier to understand this problem if you finished Segment Tree Buildand Segment Tree Queryfirst.
样例
对于数组 [0, 空,2, 3]
, 对应的线段树为:
[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]内的元素个数,其实就是对连续点的统计,所以可用线段树来求解。
要用递归求解,所以先要分析出基准情形,然后递归调用;要利用线段树的性质,采用二分法判断,逐步递归调用。
思路理清楚,代码很简单:
/** * Definition of SegmentTreeNode: * class SegmentTreeNode { * public: * int start, end, count; * SegmentTreeNode *left, *right; * SegmentTreeNode(int start, int end, int count) { * this->start = start; * this->end = end; * this->count = count; * this->left = this->right = NULL; * } * } */ class Solution { public: /** *@param root, start, end: The root of segment tree and * an segment / interval *@return: The count number in the interval [start, end] */ /* 思路:当遇到一些关于对连续点的修改和统计的问你题时,可以考虑用线段树来解决。 这里题目要求找到数组中在区间[start, end]内的元素个数,其实就是对连续点的统计,所以可用线段树来求解。 要用递归求解,所以先要分析出基准情形,然后递归调用; */ int query(SegmentTreeNode *root, int start, int end) { // write your code here //若根节点为空或者区间不符合要求return 0; if(!root||start>end){ return 0; } //特殊情况:如果所要求的区间范围包含了节点的区间范围,直接返回count if(start<=root->start&&end>=root->end){ return root->count; } //一般情况,利用二分法来判断; int mid=root->start+(root->end-root->start)/2; if(start>mid){ //情况1:如果所要求的区间在右半部分; return query(root->right,start,end); } else if(end<mid+1){ //情况2:如果所要求的区间在左半部分; return query(root->left,start,end); } //情况3:如果所要求的区间左右两半部分,也就是利用线段树的求和性质; else return query(root->left,start,mid)+query(root->right,mid+1,end); } };