求子数组最大异或和,要求时间复杂度为O(n)
class Node
{
public:
Node()
{
next[0] = NULL;
next[1] = NULL;
}
//构造之前所有异或和的前缀树
void addnum(int num)
{
Node* trytree = this;
for (int i = 31; i >= 0; i--)//应该确保高位尽量为1,所有应该从高位开始找,所以前缀树应该从高位开始构造
{
int curbit = (num >> i) & 1;
trytree->next[curbit] = trytree->next[curbit] ? trytree->next[curbit] : new Node();
trytree = trytree->next[curbit];
}
}
//获取最大异或和
int getmax(int ero)
{
int res = 0;
Node* trytree = this;
for (int i = 31; i >= 0; i--)
{
int cur = (ero >> i) & 1;
int best = i == 32 ? cur : (cur ^ 1);
best= trytree->next[best] ? (best): (best^1);//如果best边不存在则!best边一定存在,因为int是32位的,每一个点必有一条边可以走,而初始化保证了一定存在32条边,33个点
res |= best^cur<<i;//ero和之前的最优异或和异或并将其赋值给res,注意要将异或结果移到相应的位上
trytree = trytree->next[best];//遍历下一条边
}
return res;
}
//计算所有0-i的子数组的最大异或和,并找出其中最大的
int getallmax(vector<int> arr)
{
if (arr.empty())
return 0;
int max = arr[0];//当子数组不包括空数组时,max应该用数组的第一个元素进行初始化,以保证不包括空数组的最大异或和为负数时,能得到正确的值。而当子数组包括空数组时应该用0初始化
int ero = 0;
addnum(0);//初始化前缀树,才能调用getmax
for (int i = 0; i < arr.size(); i++)
{
ero ^= arr[i];
max = std::max(max, getmax(ero));
addnum(ero);
}
return max;
}
private:
Node* next[2];
};