You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].
Example
Example 1
Input: [5, 2, 6, 1]
Output: [2, 1, 1, 0]
Explanation:
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.
Example 2
Input: [1, 2, 3, 4]
Output: [0, 0, 0, 0]
思路: O(NlogN)算法沿用Count of Smaller numbers 和 count of smaller numbers before self。还是用线段树求解,但是这个题目有负数的情况,解决方法很简单,就是求得max和min之后,把整个数组解空间往右shift min位子就可以了。注意如果min > 0, 那么没必要shift; 那么segment tree的class一点都不需要改变,只需要把count的代码,每次+ Math.abs(min);把before的代码稍微改改就可以用了,注意题目要求是逆着count,所以list add的时候是add(0,count);
class Solution {
public List<Integer> countSmaller(int[] nums) {
List<Integer> list = new ArrayList<Integer>();
if(nums == null || nums.length == 0) {
return list;
}
int minvalue = nums[0], maxvalue = nums[0];
for(int i : nums) {
minvalue = Math.min(minvalue, i);
maxvalue = Math.max(maxvalue, i);
}
// 因为有负数,所以需要shift 坐标 math.abs(minvalue), 但是如果minvalue > 0,则没必要shift;
minvalue = Math.min(minvalue, 0);
int size = maxvalue - minvalue + 1;
SegmentTree tree = new SegmentTree(size);
for(int i = nums.length - 1; i >= 0; i--) {
if(nums[i] == minvalue) {
list.add(0, 0);
} else {
list.add(0, tree.querySum(0, nums[i] + Math.abs(minvalue) - 1));
}
tree.add(nums[i] + Math.abs(minvalue), 1);
}
return list;
}
private class SegmentTreeNode {
public int start, end;
public int sum;
public SegmentTreeNode left, right;
public SegmentTreeNode(int start, int end) {
this.start = start;
this.end = end;
}
}
private class SegmentTree {
public SegmentTreeNode root;
public int size;
public SegmentTree(int size) {
this.size = size;
this.root = buildTree(0, size - 1);
}
private SegmentTreeNode buildTree(int start, int end) {
if(start > end) {
return null;
}
SegmentTreeNode root = new SegmentTreeNode(start, end);
if(start == end) {
return root;
}
int mid = start + (end - start) / 2;
root.left = buildTree(start, mid);
root.right = buildTree(mid + 1, end);
return root;
}
private int querySum(SegmentTreeNode root, int start, int end) {
if(root.start == start && root.end == end) {
return root.sum;
}
int mid = root.start + (root.end - root.start) / 2;
int leftsum = 0, rightsum = 0;
if(start <= mid) {
leftsum = querySum(root.left, start, Math.min(mid, end));
}
if(end >= mid + 1) {
rightsum = querySum(root.right, Math.max(start, mid + 1), end);
}
return leftsum + rightsum;
}
private void add(SegmentTreeNode root, int index, int value) {
if(root.start == root.end && root.end == index) {
root.sum += value;
return;
}
int mid = root.start + (root.end - root.start) / 2;
if(index <= mid) {
add(root.left, index, value);
} else {
add(root.right, index, value);
}
root.sum = root.left.sum + root.right.sum;
}
public int querySum(int start, int end) {
return querySum(root, start, end);
}
public void add(int index, int value) {
add(root, index, value);
}
}
}