简介
使用了树状数组.
参考链接
https://www.cnblogs.com/xenny/p/9739600.html
TIPS
不建议看我的建议看参考链接, 因为我自己也没有很搞懂
树状数组有两个很重要的函数
int lowbit(int x){
return x&(-x);
}
返回 x 的层数信息.
单点更新
// 单点更新:将 index 这个位置 + 1
public void update(int i, int delta) {
// 从下到上,最多到 size,可以等于 size
while (i <= this.len) {
tree[i] += delta;
i += lowbit(i);
}
}
区域查询
// 区间查询:查询小于等于 index 的元素个数
// 查询的语义是"前缀和"
public int query(int i) {
// 从右到左查询
int sum = 0;
while (i > 0) {
sum += tree[i];
i -= lowbit(i);
}
return sum;
}
i -= lowbit(i); // 是什么意思呢? 个人理解, 就是 比如 4(100) 节点 覆盖范围是 1 2 3 4, 找到他前面一个区域 , 就是0,
对于 5 节点, 找到他前面的一个区域 101 - 1 = 100 (4) 就是4区域.
可以通过 + lowbit() - lowbit 找到 前面的区域 与 后面的区域.
对于此题 最后的tree为
[0, 1, 2, 1, 4];
分别对应 左右理解得映射一下
1区域有1
2区域有2(2)个元素 分别是 1 和 2
3区域有1个元素
4区域有4个元素(A1, A2,A3, A4)
因为查询的时候, 还没有填充完毕, 查询的按照未完成的样式查询(QU:其实不太懂)
查询
5261 的映射 3241
对于1的
update tree数组
011010
查询 0 得到 0
对于4
update tree 数组
011020
查询 3 和 2
得到 1
对于 2
update tree 数组
012030
查询1得到1
对于3
update tree数组
012140
此时所有的数据填充完毕, 对于3 只用查询 2
此时2为 2
GU:猜测
感觉是, 边填充, 边用树状数组查询的算法.
code
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class Solution {
public List<Integer> countSmaller(int[] nums) {
List<Integer> res = new ArrayList<>();
int len = nums.length;
if (len == 0) {
return res;
}
// 使用二分搜索树方便排序
Set<Integer> set = new TreeSet();
for (int i = 0; i < len; i++) {
set.add(nums[i]);
}
// 排名表
Map<Integer, Integer> map = new HashMap<>();
int rank = 1;
for (Integer num : set) {
map.put(num, rank);
rank++;
}
FenwickTree fenwickTree = new FenwickTree(set.size() + 1);
// 从后向前填表
for (int i = len - 1; i >= 0; i--) {
// 1、查询排名
rank = map.get(nums[i]);
// 2、在树状数组排名的那个位置 + 1
fenwickTree.update(rank, 1);
// 3、查询一下小于等于“当前排名 - 1”的元素有多少
res.add(fenwickTree.query(rank - 1));
}
Collections.reverse(res);
return res;
}
private class FenwickTree {
private int[] tree;
private int len;
public FenwickTree(int n) {
this.len = n;
tree = new int[n + 1];
}
// 单点更新:将 index 这个位置 + 1
public void update(int i, int delta) {
// 从下到上,最多到 size,可以等于 size
while (i <= this.len) {
tree[i] += delta;
i += lowbit(i);
}
}
// 区间查询:查询小于等于 index 的元素个数
// 查询的语义是"前缀和"
public int query(int i) {
// 从右到左查询
int sum = 0;
while (i > 0) {
sum += tree[i];
i -= lowbit(i);
}
return sum;
}
public int lowbit(int x) {
return x & (-x);
}
}
public static void main(String[] args) {
int[] nums = new int[]{5, 2, 6, 1};
Solution solution = new Solution();
List<Integer> countSmaller = solution.countSmaller(nums);
System.out.println(countSmaller);
}
}