Give you an integer array (index from 0 to n-1, where n is the size of this array, value from 0 to 10000) . For each element Ai
in the array, count the number of element before this element Ai
is smaller than it and return count number array.
这个题目并不难。也不是一个很好的题目。有为了做题而做题的嫌疑。但是是一个综合练习seg-tree的题目。
在之前的练习里已经熟悉了seg-tree的build 与 query方法,这个题目有一点地方比较绕,尽管知道了 构造tree的root范围应该是start = 0, end = 10000,
一开始花了很久我也没有想到的是,如果我们事先建好了整个tree,最后再去query的话,是无法得到正确结果的,我们只能得到整个array里比某元素小的数的个数。
所以这棵树必须是边建立边查询的(array 从左往右扫),这样才能保证每次查询时候,树里只有其左边部分信息,也就是符合了要求。
public class Solution {
/**
* @param A: An integer array
* @return: Count the number of element before this element 'ai' is
* smaller than it and return count number array
*/
class SegmentTreeNode {
public int start, end;
public int count;
public SegmentTreeNode left, right;
public SegmentTreeNode(int start, int end, int count) {
this.start = start;
this.end = end;
this.count = count;
this.left = this.right = null;
}
}
SegmentTreeNode root;
public SegmentTreeNode build(int start, int end) {
SegmentTreeNode root = new SegmentTreeNode(start, end, 0);
if(start != end) {
int mid = (start + end) / 2;
root.left = build(start, mid);
root.right = build(mid+1, end);
} else {
root.count = 0;
}
return root;
}
public int querySegmentTree(SegmentTreeNode root, int start, int end) {
if(start == root.start && root.end == end) {
return root.count;
}
int mid = (root.start + root.end)/2;
int leftcount = 0, rightcount = 0;
if(start <= mid)
leftcount = querySegmentTree(root.left, start, Math.min(mid,end));
if(end > mid)
rightcount = querySegmentTree(root.right, Math.max(start,mid+1), end);
return leftcount + rightcount;
}
public void modifySegmentTree(SegmentTreeNode root, int index, int value) {
if(root.start == index && root.end == index) {
root.count += value;
return;
}
int mid = (root.start + root.end) / 2;
//end up in left part
if(root.start <= index && index <=mid) {
modifySegmentTree(root.left, index, value);
}
//end up in right part
if(mid < index && index <= root.end) {
modifySegmentTree(root.right, index, value);
}
//otherwise no effect on current subtree
root.count = root.left.count + root.right.count;
}
//Notice, this method will only be used once. The built up tree can't be re-used
//We are updating(building value part) the tree while we are scanning over the array,that's why we can track left part because so far we only have info. on left part.which means after processing one more entry, the tree now can't give right info on previous entries any more.
public ArrayList
countOfSmallerNumberII(int[] A) {
root = build(0, 10000);
ArrayList
ans = new ArrayList
();
int res;
for(int i = 0; i < A.length; i++) {
res = 0;
if(A[i] > 0) {
//get count of values smaller than A[i] and in the front part of array
res = querySegmentTree(root, 0, A[i]-1);
}
//update current value into tree structure
modifySegmentTree(root, A[i], 1);
ans.add(res);
}
return ans;
}
}