二进制Trie树
一个整数类型可以看做一个固定长度的二进制串,因此可以使用Trie树以二进制的形式保存整型元素。这种数据结构可以与位运算相互配合。
LeetCode421. Maximum XOR of Two Numbers in an Array
Given an integer array nums, return the maximum result of nums[i] XOR nums[j], where 0 ≤ i ≤ j < n.
1 <= nums.length <= 2 * 104
0 <= nums[i] <= 231 - 1
题解
将每个数组元素看做一个31位的二进制串,插入Trie树中。
对于一个数,求其与Trie树中的元素的异或值的最大值。
则其从30位遍历到0位,总是优先取每一位的相反值,则走到Trie树的叶子节点时,得到的就是与其异或值最大的数组元素。
code
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int pow2[31];
pow2[0] = 1;
for (int i = 1; i <= 30; i++)
pow2[i] = 2*pow2[i-1];
int sons[32*nums.size()+10][2];
memset(sons, 0, sizeof(sons));
int size = 1, maxn = 0, cur, total;
for (int num:nums)
{
int cur = 0;
for (int i = 30; i >= 0; i--)
{
int bit = (pow2[i]&num) > 0;
if (!sons[cur][bit])
{
sons[cur][bit] = size++;
}
cur = sons[cur][bit];
}
}
for (int num:nums)
{
cur = 0, total = 0;
for (int i = 30; i >= 0; i--)
{
int bit = (pow2[i]&num) > 0;
if (sons[cur][1-bit])
{
total += pow2[i];
cur = sons[cur][1-bit];
}
else
{
cur = sons[cur][bit];
}
}
maxn = max(maxn, total);
}
return maxn;
}
};
LeetCode1707. Maximum XOR With an Element From Array
nums是一个包含非负整数的数组。queries是一个查询数组。给定nums和queries要求给出查询结果。
每个查询queries[i]=[xi,mi],询问nums中不大于mi的元素与xi的异或值的最大值。如果所有元素都大于mi,返回-1。
题解
对nums进行排序;对queries根据mi进行排序,并且保存原来的位置信息。
则按序将nums中的元素插入Trie树,同时按序执行查询query,并且保证所有不大于query.m的元素都在Trie树中时,大于query.m的元素则还未插入树中。
那么每次查询的求法就与上题相同。
代码
// 对queries根据mi排序,对nums排序。
// 依次将nums插入trie树,同时查看query, 当trie树中的元素都小于query.mi而数组剩余元素大于query.mi时,从trie树中找目标值。
bool cmp(const vector<int>& lhs, const vector<int>& rhs)
{
return lhs[1]<rhs[1];
}
class MyTrie {
private:
int pow2[31];
int sons[32 * 100000 + 10][2];
int size;
public:
MyTrie()
{
pow2[0] = 1;
for (int i = 1; i < 31; i++)
pow2[i] = 2*pow2[i-1];
memset(sons, 0, sizeof(sons));
size = 1;
}
void insert(int num)
{
int cur = 0;
for (int i = 30; i >= 0; i--)
{
int bit = (num & pow2[i]) >0;
if (!sons[cur][bit])
sons[cur][bit] = size++;
cur = sons[cur][bit];
}
}
int maxXor(int x)
{
if (size == 1) return -1;
int cur = 0, total = 0;
for (int i = 30; i >= 0; i--)
{
int bit = (x & pow2[i])>0;
if (sons[cur][1-bit])
{
cur = sons[cur][1-bit];
total += pow2[i];
}
else
{
cur = sons[cur][bit];
}
}
return total;
}
};
class Solution {
public:
vector<int> maximizeXor(vector<int>& nums, vector<vector<int>>& queries) {
sort(nums.begin(), nums.end());
for (int i = 0; i < queries.size(); i++) queries[i].push_back(i);
sort(queries.begin(), queries.end(), cmp);
vector<int> res(queries.size());
MyTrie mytrie;
int idx = 0;
for (int i = 0; i < queries.size(); i++)
{
while (idx < nums.size() && nums[idx] <= queries[i][1])
mytrie.insert(nums[idx++]);
res[queries[i][2]] = mytrie.maxXor(queries[i][0]);
}
return res;
}
};
1803. Count Pairs With XOR in a Range
Given a (0-indexed) integer array nums and two integers low and high, return the number of nice pairs.
A nice pair is a pair (i, j) where 0 <= i < j < nums.length and low <= (nums[i] XOR nums[j]) <= high.
- 1 <= nums.length <= 2 * 104
- 1 <= nums[i] <= 2 * 104
- 1 <= low <= high <= 2 * 104
题解
一个技巧:Cnt([low, high]) == Cnt((-, high+1)) - Cnt((-, low))。
因此可以将问题转化为给定上限upper和一个数x,计算数组nums中与x的异或值小于upper的元素的数量。
建立Trie树,并为每个节点(前缀)维护一个值表示具有该种前缀的元素数量。而问题的解其实是有限个长度不等的前缀所指向的元素的数量之和。
代码
class Trie {
public:
int childs[32 * 2 * 10000 + 10][2];
int size = 0;
int cnt[32 * 2 * 10000 + 10];
int pow2[20];
int bit_max = 18;
Trie()
{
memset(childs, 0, sizeof(childs));
memset(cnt, 0, sizeof(cnt));
size = 1;
pow2[0] = 1;
for (int i = 1; i < 20; i++)
pow2[i] = 2 * pow2[i-1];
}
void insert(int num)
{
int cur = 0;
cnt[cur]++;
for (int i = bit_max; i >= 0; i--)
{
int bit = (pow2[i] & num) > 0;
if (!childs[cur][bit]) childs[cur][bit] = size++;
cur = childs[cur][bit];
cnt[cur]++;
}
}
// 与num异或值小于upper的元素数量. [0, upper)
int getCnt(int num, int upper)
{
if (!upper) return 0;
int cur = 0, res = 0;
for (int i = bit_max; i >= 0; i--)
{
int bit = (pow2[i] & num) > 0; // num的第i位
if (upper > pow2[i])
{
if (childs[cur][bit]) res += cnt[childs[cur][bit]];
upper -= pow2[i];
if (childs[cur][1-bit]) cur = childs[cur][1-bit];
else return res;
}
else
{
if (childs[cur][bit]) cur = childs[cur][bit];
else return res;
}
}
return res+cnt[cur];
}
};
class Solution {
public:
int countPairs(vector<int>& nums, int low, int high) {
int res = 0;
Trie trie;
for (int num:nums)
{
res += (trie.getCnt(num, high+1) - trie.getCnt(num, low));
trie.insert(num);
}
return res;
}
};