zoukankan      html  css  js  c++  java
  • AcWing 143. 最大异或对

    题目传送门

    一、分析思路

    //最大异或对,用暴力是超时的
    for(int i=0;i<n;i++)
       for(int j=0;j<i;j++)
          res=max(res,a[i]^a[j]);
      cout<<res<<endl;
    

    结果不出意外,(TLE),只能想办法进行优化

    题解思路:

    1、将整数解析为二进制数,即有符号整数,(31)位,就是(0-30),按(Trie)树进行存储。 整数的(Trie)树存储

    2、每个数字的每一个二进制位,需要从高位到低位,即for(int i = 30; i >= 0; i--),想像一下你在构建一个(Trie)树,那么根(root)就是最高位,然后一路走到(31)位,就是最低位。

    3、每个数字想要找到与自己形成最大异或值的另一个数字,我们现在已经把它们保存到(Trie)树里了,那怎么找呢?什么样的两个数字才是最大异或值的对呢?就是每一位完全相反的就肯定是最大的异或对!那如果某一位不相反呢?这就是退而求其次的思路了,我们尽量从左到右找出与当前数字本位相反的路径,如果存在,就继续探索,如果不存在,那就使用一样的本位值。这样下来,到(31)位,就可以找到和自己匹配最大的异或值。

    总结一下
    (1)(Trie)里可以用来保存数字,数字需要通过二进制(由高位到低位)进行保存。

    (2)增加一个数字进来,其实就是增加了一个层级为(31)级的“模拟字符串”。

    (3)放入一个数字,那么它肯定会在任意一级(共(31)级)存在一边,另一边可能存在,也可能不存在。存在是因为另一个数字在那边。也可能没有数字在另一边。

    二、C++ 代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    //M代表节点的最终个数,因为一共N个数字,每个数字的转为二进制都是31位
    //首位一般用于符号,所以不是32,N*31就是M了
    const int N = 100010;
    const int M = N * 31;
    
    int n, res;
    int a[N];
    int son[M][2];
    int idx;
    
    //构建数字二进制位的Trie树
    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;//构建Trie树
            p = son[p][u];
        }
    }
    
    //所谓与x异或最大,就是利求在高位上尽量不一样,如果找不到不一样的,就只能找一样的,下一个继续优先找不一样的
    //在Trie树中查找到与x异或最大的数
    int query(int x) {
        int p = 0, ans = 0;
        for (int i = 30; i >= 0; i--) {
            int u = x >> i & 1;     //取出x的每一位,看看是0还是1
            if (son[p][!u]) {       //如果存在可以异或的路可以走的话
                p = son[p][!u];
                ans = ans * 2 + !u; //还原二进制数字为十进制
            } else {
                p = son[p][u];      //否则只能走与自己本位一样的路线
                ans = ans * 2 + u;  //还原二进制数字为十进制
            }
        }
        return ans;
    }
    
    int main() {
        //读入优化
        ios::sync_with_stdio(false);
    
        cin >> n;
        for (int i = 0; i < n; i++) cin >> a[i];
    
        //构建Trie树
        for (int i = 0; i < n; i++) insert(a[i]);
    
        //找出每个数字的最大异或对,与异或值
        for (int i = 0; i < n; i++) {
            int t = query(a[i]);//取出与a[i]异或值最大的数字t
            //打擂台,看看哪组异或值最大
            res = max(res, a[i] ^ t);
        }
        printf("%d
    ", res);
        return 0;
    }
    
  • 相关阅读:
    Java基础学习总结(41)——JPA常用注解
    Java基础学习总结(41)——JPA常用注解
    【云速建站】视频播放专题
    一招教你如何修复MySQL slave中继日志损坏问题
    【nodejs原理&源码赏析(3)】欣赏手术级的原型链加工艺术
    【云速建站】后台数据批量导入导出
    【云速建站】会员注册弹窗添加及设置
    【nodejs原理&源码赏析(2)】KOA中间件的基本运作原理
    【nodejs原理&源码赏析(1)】Express中间件系统的基本实现
    补习系列(5)-springboot- restful应用
  • 原文地址:https://www.cnblogs.com/littlehb/p/15267953.html
Copyright © 2011-2022 走看看