AcWing 143.最大异或数 题解

题目描述

AcWing 143.最大异或数 题解_第1张图片


解题思路

暴力做法

把输入的所有数,每两个两个进行异或,算出最大值
时间复杂度:O(n2

巧妙解法

将每个数看成31位的二进制串,将它存储在Trie树上
遍历一遍输入的数,对每个数,去Trie树从根节点开始尽可能地找“不同地分支”
一直找到树地叶结点为止,然后求出最大值即可
对每个数地遍历时间复杂度为O(n),在树里面遍历时间复杂度为logn
因此时间复杂度被降为O(nlogn


代码:

#include 
#include 

using namespace std;

const int N = 100010, M = 3100010;

int n;
int a[N], son[M][2], idx;

void insert(int x)
{
    int p = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int &s = son[p][x >> i & 1];
        if (!s) s = ++ idx;
        p = s;
    }
}

int search(int x)
{
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int s = x >> i & 1;
        if (son[p][!s])
        {
            res += 1 << i;
            p = son[p][!s];
        }
        else p = son[p][s];
    }
    return res;
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &a[i]);
        insert(a[i]);
    }

    int res = 0;
    for (int i = 0; i < n; i ++ ) res = max(res, search(a[i]));

    printf("%d\n", res);

    return 0;
}

代码的解释:

  • 输入的数的量级为105,每个数化成二进制串,长度在0-31(取不到31)之间,所以存储在Trie树中的结点数目最大为:105X30=3*106(实际上远远达不到)
  • 利用移位运算将每个数代表的二进制串存到Trie树上,可以巧妙利用位运算符>>k&1
  • 想要异或最大,其实就是每次尽量走不同的分支,不存在不同的分支才走相同的
  • 默认所有数字都是长度为32的01串,达不到32位的高位默认为0即可,在Trie树中是从高位往低位存储的,所以每层数字对结果的影响是逐层降低的,最高层最高,这也是后面逐层找不同路的贪心算法的基础。
    所以这棵Trie树的所有叶子结点所在的层数是一样的从根节点到叶子,所表示的每个数的这条路径上的结点数、边数是相同的

你可能感兴趣的:(code,刷题,总结&记录,算法,c++,Trie)