NBUT - 1597 Find MaxXorSum(01字典树&两两异或最大值)

[1597] Find MaxXorSum
时间限制: 2000 ms 内存限制: 65535 K
问题描述
Given n non-negative integers, you need to find two integers a and b that a xor b is maximum. xor is exclusive-or.
输入
Input starts with an integer T(T <= 10) denoting the number of tests.
For each test case, the first line contains an integer n(n <= 100000), the next line contains a1, a2, a3, ……, an(0 <= ai <= 1000000000);
输出
For each test case, print you answer.
样例输入
2
4
1 2 3 4
3
7 12 5
样例输出
7
11

题意:给出1e5个数,每个数小于等于1e9,求任意两个值使其异或值最大。

又是经典的给一堆数求某运算最大问题。也是经典的01字典树求异或和最大问题。听说曾作为今日头条的面试算法问题的开胃菜。

首先按照每个数的二进制建树,倒着从最高位开始建,因为不超过1e9的值,算每个数的二进制位31位,根节点是最高位,向下叶子节点为最低位。因为在求异或值时要尽量使得高位存在1。这也符合遍历数的顺序。

建树完成后就开始对每个数遍历,对1e5个数分别从根节点开始走,如果该数的当前位为1,那么查询树上同位是否有数存在0,也就是查询同一个父亲的另一个节点是否存在,如果存在则这一位置1,接着继续按照那个节点往下走,判断下一位和我们遍历的数相比是否存在相反的节点。

最后得到每一个数可以匹配到的最大异或值,输出即可。

对于查询的过程,如果对字典树有了解的话,都知道字典树是对单词的记录,查询时按照字符串匹配,不断往下走节点进行操作。 如此看来,01字典树在求异或时也是如此,我们记录了所有数字,现在对于一个要查询的数,求异或,那么就尽量从最高位开始使其在字典树中找到相同位置不同的节点,比如要给出的数是00001001010110,那么我们在字典树上就应该尽量找到11110110101001这样的遍历序列,如果某一位并不存在这样的节点,那只好有啥走啥,争取在后面的位中尽量取相反的匹配即可。

这里利用了字典树存储位数相同数节约空间的特点,同时也利用了字典树对大量数据方便查找的特点,既然无法对一个一个数进行n^2的一一比较,那么就把这些数存在字典树上。比较高位就比较了大量一样的数的高位。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int num[maxn],n;
int tre[maxn<<4][2];
int tot;
void insert(int a,int rt)
{
    for(int i=31;i>=0;i--)
    {
        int x=(a>>i)&1;
        if(!tre[rt][x])tre[rt][x]=++tot;
        rt=tre[rt][x];
    }
}
int finds(int a,int rt)
{
    int res=0;
    for(int i=31;i>=0;i--)
    {
        int x=(a>>i)&1;
        res<<=1;
        if(tre[rt][!x])rt=tre[rt][!x],res++;
        else rt=tre[rt][x];
    }
    return res;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        tot=0;
        int rt=++tot;
        memset(tre,0,sizeof tre);
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&num[i]),insert(num[i],rt);
        int ans=0;
        for(int i=0;i<n;i++)
            ans=max(ans,finds(num[i],rt));
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/81355059