数据结构与算法之字典树-3

111 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第27天,点击查看活动详情

2.3.4解题

0-1字典树实现好后,这道题那就很简单了,我们把数组每个元素都放入0-1字典树当中,每次插入x时都计算一下x的最大异或值,并使用ans保存每次插入中的最大异或值,最终ans即所求。

实现代码:

java:

import java.util.*;
​
//结点类
class TireNode {
    public TireNode[] next = new TireNode[2];
    
    public TireNode() {}
}
​
//Tire类
class Tire {
    //根结点
    public TireNode root = new TireNode();
    
    
    //插入操作
    public void insert(int val) {
        TireNode cur = root;
        
        for (int i = 30; i >= 0; --i) {
            //获取第i位的二进制数
            int u = (val >> i) & 1;
            
            //如果不存在则创建
            if (cur.next[u] == null) cur.next[u] = new TireNode();
            
            //更新cur
            cur = cur.next[u];
        }
    }
    
    //查询操作 返回val异或最大时的另外一个操作数
    public int query(int val) {
        TireNode cur = root;
        //储存最大异或操作数的值
        int res = 0;
        for (int i = 30; i >= 0; --i) {
            //获取对应位的二进制
            int t = (val >> i) & 1;
            //与t不同的二进制
            int u = -t + 1;
            
            if (cur.next[u] != null) {
                //优先选择不同位
                res = res * 2 + u;
                cur = cur.next[u];
            } else {
                //下策选择相同位
                res = res * 2 + t;
                cur = cur.next[t];
            }
        }
        
        return res;
    }
}
​
//Main类
class Main {
    private static Tire tire = new Tire();
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int ans = 0;
        int n = sc.nextInt();
        
        while (n-- > 0) {
            int a = sc.nextInt();
            //插入操作
            tire.insert(a);
            //查询最大异或值
            int ret = tire.query(a) ^ a;
            ans = ret > ans ? ret : ans;
        }
        
        //输出
        System.out.println(ans);
    }
}

c++:

const int N = (int) 1e6 + 2333, M = 31 * N;
​
//结点
class TireNode 
{
public:
    TireNode* next[2] = {nullptr};
    
    TireNode() {}
};
​
//Tire类
class Tire 
{
public:
    //根结点
    TireNode* root = new TireNode();
    
    //插入操作
    void insert(int val) 
    {
        TireNode* cur = root;
        
        for (int i = 30; i >= 0; --i)
        {
            //获取第i位的二进制
            int u = (val >> i) & 1;
            //如果对应的next元素为空,则新增
            if (cur->next[u] == nullptr) cur->next[u] = new TireNode();
            
            //更新cur
            cur = cur->next[u];
        }
    }
    
    //查询操作 返回与val异或最大时的另外一个操作数
    int query(int val)
    {
        TireNode* cur = root;
        int res = 0;
        for (int i = 30; i >= 0; --i)
        {
            //获取第i位的二进制
            int t = (val >> i) & 1;
            //获取与t不同的二进制位
            int u = -t + 1;
            
            if (cur->next[u] != nullptr) 
            {
                //优先选择不同位
                res |= (u << i);
                cur = cur->next[u];
            } else 
            {
                //迫不得已选相同
                res |= (t << i);
                cur = cur->next[t];
            }
        }
        return res;
    }
};
​
​
class Solution {
public:
    int findMaximumXOR(vector<int>& nums) {
        Tire tire;
        int ans = 0;
        for (int x : nums) 
        {
            tire.insert(x);
            int t = tire.query(x);
            int ret = t ^ x;
            ans = max(ret, ans);
        }
​
        return ans;
    }
};

2.3.5使用数组实现0-1字典树

当然在竞赛当中常常使用数组来实现0-1字典树,按照插入顺序为每个结点idx编号即可,N为字符串的所有输入字符串的最大长度,所以字典树的结点个数最大为N,那么最多可能也就是有Nnext数组,代码中nes二维数组表示对应着前面的next数组,只不过把所有的结点的next数组都集中在一起罢了,所以我们也可以使用编号为每一个结点分配next数组。

Java代码:

class Solution {
    //使用数组实现
    private static final int N = (int) 1e5 + 233;
    private static final int M = 31 * N;
​
    private static int[][] nes = new int[M][2];
    //结点id
    private static int idx;
​
    //插入
    private static void insert(int val) {
        int cur = 0;
        for (int i = 30; i >= 0; i--) {
            int t = (val >> i) & 1;
​
            if (nes[cur][t] == 0) nes[cur][t] = ++idx; 
​
            cur = nes[cur][t];
        }
    }
​
    //查询最大的异或值
    private static int query(int val) {
        int cur = 0;
        int ret = 0;
        for (int i = 30; i >= 0; i--) {
            int t = (val >> i) & 1;
            //获取不同的位
            int u = -t + 1;
​
            //从高位开始找,优先找不同的位
            if (nes[cur][u] != 0) {
                ret = ret * 2 + u;
                cur = nes[cur][u];
            } else {
                ret = ret * 2 + t;
                cur = nes[cur][t];
            }
        }
        return ret;
    }
​
    //初始化
    public Solution() {
        for (int i = 0; i <= idx; i++) {
            Arrays.fill(nes[i], 0);
        }
        idx = 0;
    }
    public int findMaximumXOR(int[] nums) {
        //建树
        int ans = 0;
        for (int i = 0; i < nums.length; i++) {
            insert(nums[i]);
            //查询最大异或值
            int t = query(nums[i]);
            int xor = t ^ nums[i];
            //System.out.println(nums[i]);
            ans = Math.max(xor, ans);
        }
       return ans;
    }
}

C++实现代码:

const int N = (int) 1e6 + 2333;
int nes[N][2];
int ends[N];
int idx;
​
class Solution {
private:
    void insert(int val) {
        int cur = 0;
​
        for (int i = 30; i >= 0; --i) {
            int t = (val >> i) & 1;
            if (nes[cur][t] == 0) nes[cur][t] = ++idx;
​
            cur = nes[cur][t];
        }
    }
​
    int query(int val) {
        int cur = 0;
        int ret = 0;
​
        for (int i = 30; i >= 0; --i) {
            int t = (val >> i) & 1;
            int u = -t + 1;
​
            if (nes[cur][u] != 0) {
                ret |= (u << i);
                cur = nes[cur][u];
            } else {
                ret |= (t << i);
                cur = nes[cur][t];
            }
        }
​
        return ret;
    }
​
​
public:
    Solution() {
        for (int i = 0; i <= idx; i++) {
            memset(nes[i], 0, sizeof(nes[i]));
        }
        idx = 0;
    }
​
    int findMaximumXOR(vector<int>& nums) {
        int ans = 0;
        for (int val : nums) {
            insert(val);
​
            int ret = query(val) ^ val;
            ans = ret > ans ? ret : ans;
        }
​
        return ans;
    }
};