题解
使用前缀树,这样理解前缀树比较好
x^y<=hight,定住x,找到所有符合条件的y。
如果 hBit=1,此时
- yBit=xBit,xbit^yBit=0(前面的xbit ^yBit=hBit)
从该节点过的所有路径满足条件(前面相等,此处xbit ^yBit<hBit) - xbit^yBit=1=hBit, p继续沿着yBit 向下
如果 hBit=1,此时
只能xbit^yBit=0,p继续沿着yBit 向下
== 代码有前缀树的构造==
代码
// 302-p1803. 统计异或值在范围内的数对有多少
public int countPairs(int[] nums, int low, int high) {
int res=0;
for (int i = 0; i < nums.length; i++) {
for (int j = i+1; j <nums.length ; j++) {
int i1 = nums[i] ^ nums[j];
if (i1>=low&&i1<=high){
res++;
}
}
}
return res;
}
// 法二 使用前缀树
class Trie{
Trie[] trie=new Trie[2]; // 存储的是下一层的地址
int cnt; // 存储的是经过此节点的树的个数
}
// 添加节点
Trie root=new Trie();
public void add(int num){
// 从高位到低位添加
Trie p=root;
for (int i = 14; i >=0 ; i--) {
int bit = (num >> i) & 1;
if (p.trie[bit]==null){ // 创建节点加入
p.trie[bit]=new Trie();
}
p=p.trie[bit];
p.cnt++;
}
}
// 查询 x^y<=hight 的y的个数
public int query(int x,int hight){
int sum=0;
Trie p=root;// p 当前层数
for (int i = 14; i >=0 ; i--) {
int xBit = (x >> i) & 1;
int hBit=(hight>>i)&1;
if (hBit==1){// 此时x的前缀树路径上 xBit^yBit(x,y前缀相同) 一定小于 等于 hBit
if (p.trie[xBit]!=null){
sum+=p.trie[xBit].cnt; // 就找yBit=xBit 小于
}
// yBit=xBit^1 此时 xBit^yBit=hBit
int yBit = xBit ^ 1;
if (p.trie[yBit]==null){
return sum;
}
p=p.trie[yBit];
}else {// hBit=0 此时要找 xBit^yBit=0 相等的
if (p.trie[xBit]==null){
return sum;
}
p=p.trie[xBit]; // 相同位为0 不同为1
}
}
// 当p走到最后一层
sum+=p.cnt;
return sum;
}
public int countPairs01(int[] nums, int low, int high) {
return get(nums, high) - get(nums, low - 1);
}
int get(int[] nums, int high) {
root = new Trie();
int ans = 0;
for (int i = 0; i < nums.length; i++) { // 遍历每一个元素的符合条件的个数
ans += query(nums[i], high);
add(nums[i]);
}
return ans;
}