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);
    }
};

 

 

posted @ 2017-06-27 15:29  静悟生慧  阅读(1817)  评论(0编辑  收藏  举报