天天看点

算法基础集训(第26天,共106天)------>彻底搞懂Trie树之【最大异或对】,附详细思路和图文代码解析一:概念定义 二:题目描述  三:思路分析 四:万年无误代码模板 (含详细解析)

算法基础集训(第26天,共106天)------>彻底搞懂Trie树之【最大异或对】,附详细思路和图文代码解析一:概念定义 二:题目描述  三:思路分析 四:万年无误代码模板 (含详细解析)

目录

一:概念定义 

二:题目描述 

三:思路分析 

四:万年无误代码模板 (含详细解析)

一:概念定义 

异或:两个数字转化为二进制数,从低位开始进行异或运算。异或也算也可称之为不进位加法。这题和上一题字符串统计有异曲同工之妙,两者一起食用效果较好。

二:题目描述 

在给定的 N 个整数中选出两个进行 xor(异或)运算,得到的结果最大是多少?

输入格式

第一行输入一个整数 N。

第二行输入 N 个整数 。

输出格式

输出一个整数表示答案

数据范围

1 ≤ N ≤ 10^5,

0 ≤ Ai < 2^31

输入样例

3

1 2 3

输出样例

3

三:思路分析 

这题当然有谁都能想到的朴素做法,两层for循环,但是会超时,因此需要改进算法,利用Trie树进行简化。

首先需要搞懂几个目标:

1.数字要大,说明其转化为二进制的1要尽可能多且在最高位是1的情况下位数尽可能多。

2.转化为二进制的最大数字不会超过2^31,因此最多是31位进行存储。

3.两个数字异或要尽可能大,则要求两个数字转化为二进制之后,其对应数位的数字要尽可能不同。

画一个图帮助理解内部实现:

算法基础集训(第26天,共106天)------>彻底搞懂Trie树之【最大异或对】,附详细思路和图文代码解析一:概念定义 二:题目描述  三:思路分析 四:万年无误代码模板 (含详细解析)

四:万年无误代码模板 (含详细解析)

#include <iostream>
#include <algorithm>

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 u = x >> i & 1;//从高位取数
        if (!son[p][u]) son[p][u] = ++idx;//不存在这个节点就创造这个节点
        p = son[p][u];//每次都要走到下一个节点
      }
}

int search(int x)
{
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int u = x >> i & 1;//从高位取数
        if (son[p][!u])//如果存在非的数,就往非的方向走
        {
            res += 1 << i;//将1左移i位
            p = son[p][!u];
        }
        else p = son[p][u];//不存在非的数字,只能顺势而下
    }
    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;
}
           

 创作不易,建议点赞+收藏+关注,以免找不到宝贝文章了。

基础集训结束后将开展拔高系列