對於一個數組,我們可以對其建立一棵 線段樹
, 每個結點存儲一個額外的值 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); } };