经典题,三种方法解决
- 树状数组
将数组转变成rank数组及其频率
loop from end to beginning
class Solution {
public List<Integer> countSmaller(int[] nums) {
//step1, map each unique element with rank (the smallest element rank 1)
TreeSet<Integer> ts = new TreeSet<>();
for (int num : nums) ts.add(num); //O(nlog n)
int rank = 1;
Map<Integer, Integer> rankMap = new HashMap<>();
for (int num : ts) rankMap.put(num, rank++); //O(k), k is the # of unique elements
//step2, use binary indexed tree to update and get prefix sum
List<Integer> res = new ArrayList<>();
int[] ranks = new int[ts.size() + 1]; //ranks[i] record the # of element with rank-i
for (int i = nums.length - 1; i >= 0; i--) {
int r = rankMap.get(nums[i]);
update(r, ranks); //O(log k)
int preSum = getSum(r - 1, ranks); //O(log k)
res.add(preSum);
}
Collections.reverse(res); //O(nlog n)
return res;
}
private void update(int i, int[] ranks) {
int diff = 1;
while (i < ranks.length) {
ranks[i] += diff;
i += (i & (-i));
}
}
private int getSum(int i, int[] ranks) {
int sum = 0;
while (i > 0) {
sum += ranks[i];
i -= (i & (-i));
}
return sum;
}
}
- 线段树
相同的思路,都是维持rank数组
用线段树求prefix sum
老三样,build,update 和 query
class Solution {
class TreeNode {
int begin, end, sum;
TreeNode left, right;
public TreeNode(int begin, int end, int sum) {
this.begin = begin;
this.end = end;
this.sum = sum;
}
}
public List<Integer> countSmaller(int[] nums) {
//step1, map each unique element with rank (the smallest element rank 1)
TreeSet<Integer> ts = new TreeSet<>();
for (int num : nums) ts.add(num); //O(nlog n)
int rank = 1;
Map<Integer, Integer> rankMap = new HashMap<>();
for (int num : ts) rankMap.put(num, rank++); //O(k), k is the # of unique elements
//step2, use binary indexed tree to update and get prefix sum
List<Integer> res = new ArrayList<>();
int[] ranks = new int[ts.size() + 1]; //ranks[i] record the # of element with rank-i
TreeNode root = build(0, ranks.length-1); //O(k)
for (int i = nums.length - 1; i >= 0; i--) {
int r = rankMap.get(nums[i]);
ranks[r] += 1;
update(root, r, ranks[r]); //O(log k)
int preSum = query(root, 0, r - 1); //O(log k)
res.add(preSum);
}
Collections.reverse(res); //O(nlog n)
return res;
}
private TreeNode build(int begin, int end) {
if (begin == end) {
return new TreeNode(begin, end, 0);
}
int mid = begin + (end - begin) / 2;
TreeNode root = new TreeNode(begin, end, 0);
root.left = build(begin, mid);
root.right = build(mid+1, end);
return root;
}
private void update(TreeNode root, int idx, int val) {
if (root.begin == root.end && root.begin == idx) {
root.sum = val;
return;
}
int mid = root.begin + (root.end - root.begin) / 2;
if (idx <= mid) {
update(root.left, idx, val);
} else {
update(root.right, idx, val);
}
root.sum = (root.left == null ? 0 : root.left.sum) + (root.right == null ? 0 : root.right.sum);
}
private int query(TreeNode root, int i, int j) {
if (root.end < i || root.begin > j) {
return 0;
}
if (root.begin >= i && root.end <= j) {
return root.sum;
}
return query(root.left, i, j) + query(root.right, i, j);
}
}
- 用BST
class Solution {
class TreeNode {
int val;
int dup; //当前node的重复数量
int leftCount; //leftCount用于计算小于当前node的数量
TreeNode left, right;
public TreeNode(int val) {
this.val = val;
dup = 0;
leftCount = 0;
}
}
public List<Integer> countSmaller(int[] nums) {
if (nums == null || nums.length == 0) return new ArrayList<>();
int n = nums.length;
//build root, and insert
TreeNode root = new TreeNode(nums[n-1]);
int[] res = new int[n];
for (int i = n-1; i >= 0; i--) {
res[i] = insert(root, nums[i]);
}
//change arr to list
List<Integer> ans = new ArrayList<>();
for (int num : res) ans.add(num);
return ans;
}
private int insert(TreeNode node, int val) {
int sum = 0;
while (node.val != val) {
if (node.val > val) { //小于node的数量加一
if (node.left == null) node.left = new TreeNode(val);
node.leftCount++;
node = node.left;
} else {
if (node.right == null) node.right = new TreeNode(val);
sum += node.leftCount + node.dup;
node = node.right;
}
}
node.dup++;
return sum + node.leftCount;
}
}