系统会为您提供许多查询Q ,每个查询将具有以下类型:
- 查询1 :add(x)这意味着将x添加到您的数据结构中。
- 查询2 :maxXOR(y)这表示将所有已存储在数据结构中的元素打印为y的最大可能XOR。
1 <= x,y <= 10 ^ 9
1 <= 10 ^ 5 <= Q
数据结构仅以0开头。
例子:
Input: (1 10), (1 13), (2 10), (1 9), (1 5), (2 6)
Output: 7 15
Add 10 and 13 to stream.
Find maximum XOR with 10, which is 7
Insert 9 and 5
Find maximum XOR with 6 which is 15.
解决此问题的一个好方法是使用Trie。这篇文章的前提条件是Trie插入和搜索。
每个Trie节点将如下所示:
struct TrieNode
{
// We use binary and hence we
// need only 2 children
TrieNode* Children[2];
bool isLeaf;
};
要处理的另一件事是,在存储它们之前,我们必须在每个输入数字的二进制等效项之前向左填充适当数量的零。 x或y的最大可能值为10 ^ 9,因此32位就足够了。
那么这是如何工作的呢?
假设我们必须在Trie中插入3和7。 Trie从0开始,在这三个插入之后可以像这样可视化:
为简化起见,已进行填充以使用3位存储每个数字。请注意,在二进制文件中:
3是011
7是111
现在,如果我们必须在Trie中插入1,我们可以注意到1是001,并且已经有00的路径。因此,我们为最后一个设置位创建了一个新节点,并在连接后得到:
现在,如果必须对XOR取5(即101),请注意,对于最左边的位(位置2),我们可以选择从根开始的0,然后我们向左移动。这是位置2,我们在答案中加2 ^ 2。
对于位置1,我们在5中有一个0,我们看到可以从当前节点中选择1。这样我们就可以将答案加2 ^ 1。
对于位置0,我们有一个1/5,我们看到我们不能从当前节点中选择0,因此我们向右走。
上面显示了5的路径。因此,答案是2 ^ 2 + 2 ^ 1 = 6。
// C++ program to find maximum XOR in
// a stream of integers
#include
using namespace std;
struct TrieNode
{
TrieNode* children[2];
bool isLeaf;
};
// This checks if the ith position in
// binary of N is a 1 or a 0
bool check(int N, int i)
{
return (bool)(N & (1<isLeaf = false;
temp->children[0] = NULL;
temp->children[1] = NULL;
return temp;
}
// Inserts x into the Trie
void insert(TrieNode* root, int x)
{
TrieNode* Crawler = root;
// padding upto 32 bits
for (int i = 31; i >= 0; i--)
{
int f = check(x, i);
if (! Crawler->children[f])
Crawler->children[f] = newNode();
Crawler = Crawler->children[f];
}
Crawler->isLeaf = true;
}
// Finds maximum XOR of x with stream of
// elements so far.
int query2(TrieNode *root, int x)
{
TrieNode* Crawler = root;
// Do XOR from root to a leaf path
int ans = 0;
for (int i = 31; i >= 0; i--)
{
// Find i-th bit in x
int f = check(x, i);
// Move to the child whose XOR with f
// is 1.
if ((Crawler->children[f ^ 1]))
{
ans = ans + (1 << i); // update answer
Crawler = Crawler->children[f ^ 1];
}
// If child with XOR 1 doesn't exist
else
Crawler = Crawler->children[f];
}
return ans;
}
// Process x (Add x to the stream)
void query1(TrieNode *root, int x)
{
insert(root, x);
}
// Driver code
int main()
{
TrieNode* root = newNode();
query1(root, 10);
query1(root, 13);
cout << query2(root, 10) << endl;
query1(root, 9);
query1(root, 5);
cout << query2(root, 6) << endl;
return 0;
}
7
15
Trie占用的空间为O(n * log(n))。类型1的每个查询都花费O(log(n))时间。类型2的每个查询也需要O(log(n))时间。这里n是最大的查询数。
跟进问题:如果我们给三个查询而不是两个查询怎么办?
1)add(x)这意味着将x添加到您的数据结构中(允许重复)。
2)maxXOR(y)这意味着与已经存储在数据结构中的所有元素一起打印y的最大可能XOR。
3)remove(z)这意味着从数据结构中删除z的一个实例。
Trie解决方案中的哪些更改可以实现此目的?