最大异或对

如果你觉得这篇题解对你有用,可以点个赞或关注再走呗,谢谢你的关注~## 不清楚蓝桥杯考什么的点点下方

考点秘籍

想背纯享模版的伙伴们点点下方

蓝桥杯省一你一定不能错过的模板大全(第一期)

蓝桥杯省一你一定不能错过的模板大全(第二期)

蓝桥杯省一你一定不能错过的模板大全(第三期)

蓝桥杯省一你一定不能错过的模板大全(第四期)!!!

想背注释模版的伙伴们点点下方

蓝桥杯必背第一期

蓝桥杯必背第二期

往期精彩回顾

蓝桥杯上岸每日N题 第一期(一)!!!

蓝桥杯上岸每日N题第一期(二)!!!

蓝桥杯上岸每日N题第一期(三)!!!

蓝桥杯上岸每日N题第二期(一)!!!

蓝桥杯上岸每日N题第三期(一)!!!

蓝桥杯上岸每日N题 第四期(最少刷题数)!!!

蓝桥杯上岸每日N题 第五期(山)!!!

蓝桥杯上岸每日N题 第六期(求阶乘)!!!

蓝桥杯上岸每日N题 第七期(小猫爬山)!!!

蓝桥杯上岸每日N题 第八期 (全球变暖)!!!

操作系统期末题库 第九期(完结)

LeetCode Hot100 刷题(第三期)

idea创建SpringBoot项目报错解决方案

数据库SQL语句(期末冲刺)

想看JavaB组填空题的伙伴们点点下方

填空题

竞赛干货

算法竞赛字符串常用操作大全

蓝桥杯上岸必刷!!!(模拟/枚举专题)

蓝桥杯上岸必背!!! (第三期 DP)

蓝桥杯上岸必背!!!(第四期DFS)

蓝桥杯上岸必背!!!(第五期BFS)

蓝桥杯上岸必背!!!(第六期树与图的遍历)

蓝桥杯上岸必背!!!(第七期 最短路算法)

蓝桥杯上岸必背!!!(第八期 简单数论)

蓝桥杯上岸必刷!!!(进制、数位专题)

蓝桥杯上岸考点清单 (冲刺版)!!!

分析

最大异或对

(1)最大异或对是运用trie树存储十进制数对应的二进制数的每一位
(2)再根据trie树的每一位进行搜索查找,严格满足不同的数异或为1,相同的异或为0。
(3)根据(2)进行搜索,从最高位开始搜索,尽可能地保证较高位次的异或数最大。

通过搜索,匹配每个位最大的异或数。

即从最高位开始,尽可能多地保证每一位的异或数为1,要保证这一点,就需要往当前位数不同的方向走,这样所得到的结果最大。

换句话来说,从最高位开始,往当前位数不同的方向走,如0往1,1往0的方向走,实在无不同位数就走相同位数。

trie结果唯一 及 确保选取两个数

query一个数的时候,这时该数会根据之前插进trie树的每个数的二进制数进行搜索,直至搜到叶子节点结果唯一,那这样就保证我们是选择了两个数去进行异或操作最后得到唯一的最大值。

注意!

理论上,先插入再查找和先查找再插入均可。
但在实现时,考虑到边界问题,即最开始树为空时,查找的边界问题
采用先插入再查找的方式实现,trie数左节点为0,右节点为1

分析图

模拟

最大异或对_第1张图片

res+=1<

最大异或对_第2张图片

注:把异或数为1的数位左移1相当于2i次方,再把每次枚举的每个位置的结果加起来,就可以得出最大值。

trie树在数组的体现

最大异或对_第3张图片

ACcode

import java.io.*;
public class Main{
    static int N=3100010;
    //总共是10000个数,每个数枚举对应二进制数的30个位置
    //所以总共是31000010个数
    //数组开小的话为MLE
    static int idx;
    static int son[][]=new int [N][2];
    //一定要记得是0\1两列 p到0和p到1
    public static void insert(int x){
        int p=0;
        for(int i=30;i>=0;i--){
            int u=x>>i&1;
            if(son[p][u]==0)son[p][u]=++idx;
            p=son[p][u];
        }
    }
    public static int query(int x){
        int p=0,res=0;
        for(int i=30;i>=0;i--){
            int u=x>>i&1;
            if(son[p][1-u]!=0){
                res+=1<<i;
                p=son[p][1-u];
            }
            else{
                p=son[p][u];
            }
        }
        return res;
    }
    public static void main(String []args)throws IOException{
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
        String str[]=bf.readLine().split(" ");
        int n=Integer.parseInt(str[0]);
        String s[]=bf.readLine().split(" ");
        for(int i=0;i<n;i++)
        {
            insert(Integer.parseInt(s[i]));
        }
        int res=0;
        for(int i=0;i<n;i++){
        int t=query(Integer.parseInt(s[i]));
        res=Math.max(res,t);
    }
    pw.println(res);
    pw.flush();
}
}

详解代码

import java.io.*;
public class Main{
    static int N=3100010;
    static int idx;
    static int son[][]=new int [N][2];
    public static void main(String []args)throws IOException{
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
    int n = Integer.parseInt(in.readLine());
    String s[]=in.readLine().split(" ");
    for(int i=0;i<n;i++){
        insert(Integer.parseInt(s[i]));
    }
    int res=0;
    for(int i=0;i<n;i++){
        int t = query(Integer.parseInt(s[i]));
        res=Math.max(res,t);
    }
    out.write(res+" ");
    out.close();
    }
    
    public static void insert(int x){
        int p=0;
        for(int i=30;i>=0;i--){
            int u=x>>i&1;//取出二进制数的第i位
            if(son[p][u]==0)son[p][u]=++idx;//如果还未被创建,则进行建边操作,连接两个节点,即++idx
            p=son[p][u];//往下一层走
            
        }
    }
    public static int  query(int x){
        int p=0,res=0;
        for(int i=30;i>=0;i--){
            int u=x>>i&1;
            if(son[p][1-u]!=0){
                //当u=0时,即1-0=1,往1的方向走,异或值最大。
                //son[p][1-u]用来确定1方向的
                //点是否存在,存在则进行下面操作
                //不存在则只能选择唯一的路来走
                
                //当u=1时,即1-1=0,往0的方向走,异或值最大。
                //son[p][1-u]用来确定1方向的点是否存在,存在则进行下面操作
                //不存在则只能选择唯一的路来走
                
                res+= 1<<i;//1<
                //if分支内得到的异或数为1,加上。
                //else分支内得到的异或数为0,不需要加上。
                
                p=son[p][1-u];//以此进入下一层
                
            }
            else{
                //只能选择下面唯一的路来做
                p=son[p][u];
                
            }
        }
        
        return res;
    }
    
    
}

你可能感兴趣的:(蓝桥杯上岸,蓝桥杯,刷题,eclipse,java,leetcode,数据结构,算法)