java---Trie树算法_最大异或对(每日一道算法2022.8.16)

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

输入:
3
1 2 3
输出:
3
public class Trie_最大异或对 {
    //初始化,M设置为31*N以防万一,一般用不到这么大,son设置为[M][2],代表行,2代表列,因为存储二进制只有0和1两个值
    public static int N = 100010, M = 31*N, index = 0;
    public static int[] a = new int[N];
    public static int[][] son = new int[M][2];

    public static void main(String[] args) {
        //初始化
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for (int i = 0; i<n; i++){a[i] = in.nextInt();}

        int res = 0;
        for (int i = 0; i<n; i++) {
            //注意这里是先插入后查找,这样就保证不会出现查找空Trie的情况,减少一步判断
            insert(a[i]);
            int t = search(a[i]);
            res = Math.max(res, a[i] ^ t);
        }
        System.out.println(res);
    }

    //在Trie树插入x的二进制
    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] = ++index;}
            p = son[p][u];
        }
    }


    //查找和x进行异或计算能得到最大值的result
    public static int search(int x) {
        int p = 0, res = 0;
        for (int i = 30; i>=0; i--) {
            //这里u拿到的是当前位的二进制数是1还是0,例如9的二进制1101,依次拿到1,1,0,1,原理是1101右移3,2,1,0次,每次得到0001,0011,0110,1101,然后用&1进行异或判断
            int u = x >> i & 1;
            //最好的情况是拿到和当前u相反的二进制数,也就是去son[p][反u]找,如果存在就取用,不存在就去son[p][u]找
            //在进行判断的同时,我们可以直接用res进行数的存储,例如现在是1101,下一位要么是11011,要么是11010,那么就左移一位,然后加上当前的u值即可
            //切记要加括号,加号优先级比左移高,或者直接乘2也可以达到左移的效果
            if (son[p][u ^ 1]!=0) {
                p = son[p][u ^ 1];
                res = res * 2 + (u ^ 1);
            }
            else {
                p = son[p][u];
                res = res * 2 + u;
            }
        }
        //最后返回找到的数
        return res;
    }
}

声明:算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值