假设最终的最大异或结果为 maxXOR,我们可以从最高位开始构建这个结果。我们使用一个掩码 mask 来构建当前位的前缀。初始时,mask 为 0。
对于每一位,我们通过遍历数组 nums,计算所有数的当前位前缀,然后将其加入一个集合 prefixes 中。集合 prefixes 存储了所有可能的当前位前缀。
接下来,我们假设当前位为 1,构建一个潜在的最大异或结果 potentialMax。我们通过将 maxXOR 的当前位设置为 1 来构建 potentialMax。例如,如果 maxXOR 的二进制表示为 1010,而当前位为第 3 位,那么 potentialMax 的二进制表示为 1110。
然后,我们遍历 prefixes 集合中的每个前缀 prefix。我们检查集合中是否存在一个前缀与 potentialMax ^ prefix 相等。这里的 ^ 是按位异或运算符。如果存在这样的前缀,说明最大异或结果的当前位可以为 1,我们更新 maxXOR 为 potentialMax,并跳出循环,继续处理下一位。如果不存在这样的前缀,则最大异或结果的当前位必须为 0,我们不需要更新 maxXOR,继续处理下一位。
通过这种方式,我们逐位确定了最大异或结果 maxXOR。最后,返回得到的 maxXOR 即为所求。
这种方法的时间复杂度为 O(32N) = O(N),其中 N 是数组的长度。因为一个整数的二进制表示最多有 32 位,所以我们需要进行 32 次循环来确定最大异或结果的每一位。在每一次循环中,我们需要遍历数组 nums,计算当前位的前缀,所以时间复杂度为 O(N)。总的时间复杂度为 O(32N) = O(N)。这种方法的空间复杂度为 O(1)。
cppclass Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int maxXOR = 0;
int mask = 0;
for (int i = 31; i >= 0; i--) {
mask |= (1 << i); // 构建当前位的掩码
unordered_set<int> prefixes; // 用于存储当前位前缀的集合
for (int num : nums) {
prefixes.insert(num & mask); // 将当前位的前缀加入集合
}
int potentialMax = maxXOR | (1 << i); // 假设当前位为 1
for (int prefix : prefixes) {
if (prefixes.count(potentialMax ^ prefix)) {
// 如果存在一个前缀与 potentialMax^prefix 相等
// 则最大异或值的当前位可以为 1
maxXOR = potentialMax;
break;
}
}
}
return maxXOR;
}
};
我们定义了 TrieNode 类表示 Trie 树的节点。每个节点有两个子节点,分别表示当前位为 0 和 1 时的情况。
接下来,我们定义了 Trie 类表示 Trie 树。Trie 类有一个根节点,并提供了插入和查找最大异或值的方法。
在插入方法 insert 中,我们从当前数的最高位开始遍历,将每一位作为索引,根据当前位的值选择相应的子节点。如果子节点为空,我们创建一个新的节点。然后,将当前节点移动到下一位的子节点,继续进行插入操作。最终,将整个数的二进制表示插入 Trie 树中。
在查找最大异或值的方法 findMaxXOR 中,我们从当前数的最高位开始遍历,依次判断当前位的相反位是否存在。如果存在相反位,说明最大异或值的当前位可以为 1,我们将当前位的值设为 1,并将当前节点移动到相反位的子节点。如果不存在相反位,说明最大异或值的当前位必须为 0,我们将当前位的值设为 0,并将当前节点移动到当前位的子节点。通过这样的遍历,我们可以得到最大异或值。
cppclass Solution {
public:
// Trie 节点
class TrieNode {
public:
TrieNode* next[2];
TrieNode() {
next[0] = nullptr;
next[1] = nullptr;
}
};
// Trie 树
class Trie {
public:
TrieNode* root;
Trie() {
root = new TrieNode();
}
void insert(int num) {
TrieNode* curr = root;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
if (curr->next[bit] == nullptr) {
curr->next[bit] = new TrieNode();
}
curr = curr->next[bit];
}
}
int findMaxXOR(int num) {
int maxXOR = 0;
TrieNode* curr = root;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
int oppositeBit = bit ^ 1; // 获取与当前位相反的位
if (curr->next[oppositeBit] != nullptr) {
maxXOR |= (1 << i); // 如果存在相反位,则当前位可以为 1
curr = curr->next[oppositeBit];
} else {
curr = curr->next[bit];
}
}
return maxXOR;
}
};
int findMaximumXOR(vector<int>& nums) {
Trie trie;
int maxXOR = 0;
for (int num : nums) {
trie.insert(num);
int currXOR = trie.findMaxXOR(num);
maxXOR = max(maxXOR, currXOR);
}
return maxXOR;
}
};
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!