【28. 最大异或对】

简介: 最大异或对就是在给定的数中,找到俩个数使得,这俩个数异或后的结果最大。- 一般采用`暴力法`和`字典树`的方法。

概述

  • 最大异或对就是在给定的数中,找到俩个数使得,这俩个数异或后的结果最大。
  • 一般采用暴力法字典树的方法。

暴力写法


#include <iostream>
#include <algorithm>
using namespace std;

const int N  = 100010;
int a[N];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i ++)
    {
      scanf("%d", &a[i]);
    }
    int res = 0;
    for (int i = 0; i < n; i ++)
    {
        for (int j = 0; j < i; j ++)
        {
            res = max(res, a[i] ^ a[j]);
           
        }
    }
    cout << res << endl;
    return 0;
   
}

字典树优化

建树过程

  • 从高位开始建树,因为在异或过程中(相异为1,相同为0),我们尽量满足高位最大

1661154482428.png

程序实现

void insert(int x)
{
    int p = 0;                                        //根节点
    for (int i = 30; i >= 0; i --)                    //从最大位开始找
    {
        int u = x >> i & 1;                           //取X的第i位的二进制数是什么  x>>k&1(前面的模板)
        if (!son[p][u]) son[p][u] = ++ idx;           //如果插入中发现没有该子节点,开出这条路
        p = son[p][u];                                //指针指向下一层
    }
}

查找最大异或对结果

异或

  • 俩个数都转换为二进制,如果俩个位相同异或后为0,不同异或为0。(相异为1,相同为0)

实现

  • 当根节点没有数时,我们首先插入一个数
  • 当再次插入第二个数时,应该先和插入的第一个数进行异或。
  • 再次插入第三个数时,应该和之前插入的所有数依次异或,取得最大值。

如何查找最大呢

  • 对于每一位,例如当前最高位是1,我们为了使异或后值为最大,我们就需要找最高位是0的进行异或,这样最后的结果才是最大
  • 如果异或后的数是1,最好,如果不是的话,就只能是0。

代码实现

int query(int x)
{
    int p = 0, res = 0;  //用res来存取当前路径表示的数是什么
    for (int i = 30; i >= 0; i --)                   //从最大位开始找
    {
        int u = x >> i & 1;
        if (son[p][!u])                              //如果当前层有对应的不相同的数
        {
            p = son[p][!u];                          //p指针就指到不同数的地址
            res = res * 2 + !u;                      //*2代表左移一位,加上下面一位
        }                                            //例如    001 * 2 = 0010   下一位为1,
                                                     //  0010 + 1  = 00101
                                                                                 
        else
        {
            p = son[p][u];
            res = res * 2 + u;
        }
       
    }
    return res;
}

题目

1661154512599.png

代码

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, M = 31 * N;
int son[M][2];   //M代表节点个数(M代表一个数字串二进制可以到多长),2代表分支只有俩个,一个是0,一个是1

int a[N];
int idx;

void insert(int x)
{
    int p = 0;                                        //根节点
    for (int i = 30; i >= 0; i --)                    //从最大位开始找
    {
        int u = x >> i & 1;                           //取X的第i位的二进制数是什么  x>>k&1(前面的模板)
        if (!son[p][u]) son[p][u] = ++ idx;           //如果插入中发现没有该子节点,开出这条路
        p = son[p][u];                                //指针指向下一层
    }
}

int query(int x)
{
    int p = 0, res = 0;  //用res来存取当前路径表示的数是什么
    for (int i = 30; i >= 0; i --)                   //从最大位开始找
    {
        int u = x >> i & 1;
        if (son[p][!u])                              //如果当前层有对应的不相同的数
        {
            p = son[p][!u];                          //p指针就指到不同数的地址
            res = res * 2 + !u;                      //*2代表左移一位,加上下面一位
        }                                            //例如    001 * 2 = 0010   下一位为1,
                                                     //  0010 + 1  = 00101
                                                                                 
        else
        {
            p = son[p][u];
            res = res * 2 + u;
        }
       
    }
    return res;
}
int main()
{
    int n;
    scanf("%d", &n); 
    for (int i = 0; i < n; i ++)  scanf("%d", &a[i]);
    
    int res = 0;
    for (int i = 0; i < n; i ++)
    {
        insert(a[i]);
        int t = query(a[i]);                         //query(a[i])查找的是a[i]值的最大与或值
        res = max(res, a[i] ^ t);
    }
    printf("%d\n", res);
    return 0;
   
}
目录
相关文章
|
存储 负载均衡 Cloud Native
gRPC的原理和实践
gRPC的原理和实践
1001 1
gRPC的原理和实践
|
10月前
|
Ubuntu Linux
Dpkg软件包管理工具使用指南
Dpkg是Debian和Ubuntu等Linux发行版中用于管理软件包的基本包管理工具。它直接操作.deb软件包,提供了安装、卸载、查询等功能。然而,使用dpkg时需要谨慎,因为它不会自动解决依赖关系,可能导致软件包不完整或系统不稳定。通常建议使用高级包管理工具如apt来安装、升级和移除软件包,它们会更好地处理依赖关系。但了解dpkg的基本命令对于深入理解系统管理和解决一些特定问题仍然非常重要。
434 2
|
存储 自然语言处理 索引
|
存储 算法 Java
深入解析 Java 数据结构:红黑树的特点与应用
红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,它在 Java 编程中扮演着重要的角色,用于高效地存储和管理数据。红黑树的特点使其在查找、插入和删除操作中保持相对平衡,从而提供了稳定且高效的性能。本文将深入探讨红黑树的特点、用法、实现方式以及在实际应用中的优势。
|
编解码 异构计算
System Generator初体验FIR滤波器(三)
System Generator初体验FIR滤波器
292 1
|
人工智能 自然语言处理 搜索推荐
AI之HCI:人机交互Human-Computer Interaction的简介、发展历史、案例应用之详细攻略(一)
AI之HCI:人机交互Human-Computer Interaction的简介、发展历史、案例应用之详细攻略(二)
AI之HCI:人机交互Human-Computer Interaction的简介、发展历史、案例应用之详细攻略(一)
|
PyTorch 算法框架/工具 Python
PyTorch中的forward的理解
PyTorch中的forward的理解
534 0
|
机器学习/深度学习 人工智能 算法
【BN层】基础回顾:带你认识神经网络中常见的BN层
【BN层】基础回顾:带你认识神经网络中常见的BN层
1624 0
|
存储 设计模式 人工智能
Rust 笔记:有限状态机原理/状态模式 及其 在Rust 编程中的应用
Rust 笔记:有限状态机原理/状态模式 及其 在Rust 编程中的应用
952 0
|
开发工具 数据安全/隐私保护 Windows
linphone安装和使用教程
<p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"> 刚刚搞通linphone,终于能连上sip.linphone.org了,中间过程太心酸了。</p> <p style="color:rgb(51,51,51); font-family:Arial; font-size
9298 0

热门文章

最新文章