题目
思路
该题目要求某个数字同数组中的数字异或的最大值,因此使用前缀树最为高效。如下题目也是使用前缀树来实现快速求解两个数最大异或值的,关于前缀树的构建和求解异或值最大的数的过程可以参考此博客。
如果不考虑本题目中查询请求中的最大数字限制,我们只需要将原数组的所有数加入到前缀树中,再使用上述题目中使用的搜索与n
异或结果最大的数的算法即可求得最大的异或值。不过本题目加入了一个对搜索结果的的最大值的限制 (设其为limit
),因此我们在前缀树中搜索的过程也有一些不同。
我们需要在前缀树的结点中加入一个min
字段用于记录该节点对应的子树中存储的最小数字,根据min
字段,我们就可以在搜索过程中确定是否需要搜索该子树(如果min > limit
则不搜索该子树)。另外,在创建前缀树时,每插入一个数字也需要更新各个结点的min
值。
在搜索过程中,对于数字num
第bit
位为0
时,我们首先尝试搜索前缀树结点的右子树,如果失败(没有找到结果,即右子树不存在/右子树结点min > limit
),则尝试搜索左子树;对于数字num
第bit
位为1
时,我们首先尝试搜索前缀树结点的左子树,如果失败,则尝试所有右子树。
因为有
min > limit
的限制,因此上述搜索过程并不会完全遍历整个前缀树,对于没有合法结果的子树在访问一个结点后就不会继续向下搜索了。
代码实现
struct Tier{
Tier* left;
Tier* right;
// 记录当前数存储的最小数字
int min;
Tier() {
min = INT_MAX;
left = nullptr;
right = nullptr;
}
};
class Solution {
public:
vector<int> maximizeXor(vector<int>& nums, vector<vector<int>>& queries) {
Tier* root = new Tier();
vector<int> result(queries.size());
// 将所有数字加入前缀树中
for (int i : nums) {
tier_add(root, i);
}
// 搜索每一个查询的结果
for(int i=0; i<result.size(); i++) {
result[i] = tier_find_max_with_limits(root, 0, queries[i][0], queries[i][1], 30);
// 如果没有找到合适的数,则返回-1,不再与原数字异或
if (result[i] != -1) {
result[i] ^= queries[i][0];
}
}
return result;
}
// 向前缀树中插入一个数字
void tier_add(Tier* node, int num) {
for(int i=30; i>-1; i--) {
int c = (num >> i) & 0x1;
// 更新当前树存储的最小数字
if (num < node->min) {
node->min = num;
}
if (c == 0) {
if (node->left == nullptr) {
node->left = new Tier();
}
node = node->left;
} else {
if (node->right == nullptr) {
node->right = new Tier();
}
node = node->right;
}
}
// 为最后一个结点添加最小值
if (num < node->min) {
node->min = num;
}
}
/**
@param node 前缀树根结点,
@param prefix 当前已经确定的比特位(前30~bit位)
@param num 查找目标(找到一个数与num异或值最大)
@param limit 查找结果的最大值,即返回的结果需要<= limit
@param bit 当前搜索的bit位(30 ~ 0), bit = -1表示搜索完成,找到结果
@ret 找到的与num异或值最大且<=limit的数
*/
int tier_find_max_with_limits(Tier* node, int prefix, int num, int limit, int bit) {
int c_n;
int tmp = -1;
// node == nullptr或者node->min > limit(当前数存储的最小数字<limit)表示该路径没有合适的数
if (node == nullptr || node->min > limit) {
return -1;
}
// bit == -1表示成功找到一个数,该数为prefix
if (bit == -1) {
return prefix;
}
// 其余情况则需要继续进行深度优先搜索
c_n = (num >> bit) & 0x1;
// 目标数第bit位为0
if (c_n == 0) {
// 尝试搜索前缀树中第bit位为1的数(使得异或结果最大化)
tmp = tier_find_max_with_limits(node->right, prefix | (0x1 << bit), num, limit, bit - 1);
// 没有结果则尝试搜索前缀树中第bit位为0的数
if (tmp == - 1) {
tmp = tier_find_max_with_limits(node->left, prefix, num, limit, bit - 1);
}
// 目标数第bit位为1
} else {
// 尝试搜索前缀树中第bit位为0的数(使得异或结果最大化)
tmp = tier_find_max_with_limits(node->left, prefix, num, limit, bit - 1);
// 没有结果则尝试搜索前缀树中第bit位为1的数
if (tmp == -1) {
tmp = tier_find_max_with_limits(node->right, prefix | (0x1 << bit), num, limit, bit - 1);
}
}
// 返回搜索结果
return tmp;
}
};