【Leetcode】1707. Maximum XOR With an Element From Array

题目地址:

https://leetcode.com/problems/maximum-xor-with-an-element-from-array/

给定一个长 n n n的非负整数数组 A A A,再给定一系列询问 q q q,每次询问包含两个数字 x x x m m m,要求找到 A A A中小于等于 m m m并且与 x x x异或值最大的那个数。如果不存在则返回 − 1 -1 1。题目保证询问的数字也都是非负整数。

一个比较简单的想法是用Trie,并且在每个节点里还存放一下走到当前路径的所有数的最小值。接下来询问的时候,对于每次询问 ( x , m ) (x,m) (x,m),把 x x x转为长 31 31 31的二进制数,然后从高位开始遍历,并且从Trie树根向下走,优先走与 x x x当前二进制位不同的那个分支,如果那个分支的最小值是大于 m m m的,那无解,走不了(否则就走),则考虑走另一个分支,如果那个分支的最小值也是大于 m m m的,则本次询问无解,返回 − 1 -1 1(否则就走这个分支);否则就按照上面的原则,走下去。走的同时记录异或的答案即可。代码如下:

public class Solution {
    
    
    
    class Node {
    
    
        int min;
        Node next[];
        
        public Node() {
    
    
            min = Integer.MAX_VALUE;
            next = new Node[2];
        }
    }
    
    // 将x的二进制表示插入该Trie中
    private void insert(int x) {
    
    
        Node cur = root;
        
        for (int i = 31; i >= 0; i--) {
    
    
            int idx = x >> i & 1;
            if (cur.next[idx] == null) {
    
    
                cur.next[idx] = new Node();
            }
            
            cur = cur.next[idx];
            // 更新路径最小值
            cur.min = Math.min(cur.min, x);
        }
    }
    
    private int query(int x, int lim) {
    
    
        Node cur = root;
        
        int res = 0;
        for (int i = 31; i >= 0; i--) {
    
    
            int idx = x >> i & 1;
            res <<= 1;
            if (cur.next[idx ^ 1] != null && cur.next[idx ^ 1].min <= lim) {
    
    
                cur = cur.next[idx ^ 1];
                res++;
            } else if (cur.next[idx] != null && cur.next[idx].min <= lim) {
    
    
                cur = cur.next[idx];
            } else {
    
    
                return -1;
            }
        }
        
        return res;
    }
    
    Node root;
    
    public int[] maximizeXor(int[] nums, int[][] queries) {
    
    
        root = new Node();
        for (int num : nums) {
    
    
            insert(num);
        }
        
        int[] res = new int[queries.length];
        for (int i = 0; i < res.length; i++) {
    
    
            int[] query = queries[i];
            res[i] = query(query[0], query[1]);
        }
        
        return res;
    }
}

预处理时间复杂度 O ( n ) O(n) O(n),每次询问时间 O ( 1 ) O(1) O(1),空间 O ( n ) O(n) O(n)

还有个改进的做法,就是将 A A A从小到大排序,然后将询问按照 m m m也排序,然后适当安排插入和查询的次序,这样就不用在Trie上记录最小值了。代码如下:

import java.util.Arrays;

public class Solution {
    
    
    
    class Node {
    
    
        Node next[];
        
        public Node() {
    
    
            next = new Node[2];
        }
    }
    
    private void insert(int x) {
    
    
        Node cur = root;
        
        for (int i = 31; i >= 0; i--) {
    
    
            int idx = x >> i & 1;
            if (cur.next[idx] == null) {
    
    
                cur.next[idx] = new Node();
            }
            
            cur = cur.next[idx];
        }
    }
    
    private int query(int x) {
    
    
        Node cur = root;
        
        int res = 0;
        for (int i = 31; i >= 0; i--) {
    
    
            int idx = x >> i & 1;
            res <<= 1;
            if (cur.next[idx ^ 1] != null) {
    
    
                cur = cur.next[idx ^ 1];
                res++;
            } else if (cur.next[idx] != null) {
    
    
                cur = cur.next[idx];
            } else {
    
    
                return -1;
            }
        }
        
        return res;
    }
    
    Node root;
    
    public int[] maximizeXor(int[] nums, int[][] queries) {
    
    
        root = new Node();
        
        Arrays.sort(nums);
        for (int i = 0; i < queries.length; i++) {
    
    
            queries[i] = new int[]{
    
    queries[i][0], queries[i][1], i};
        }
        Arrays.sort(queries, (q1, q2) -> Integer.compare(q1[1], q2[1]));
    
        int[] res = new int[queries.length];
        for (int i = 0, j = 0; j < queries.length; j++) {
    
    
        	// 把小于等于当前limit的数insert进Trie
            while (i < nums.length && nums[i] <= queries[j][1]) {
    
    
                insert(nums[i]);
                i++;
            }
            
            // 这样答案如果存在,就一定已经在Trie里了,直接query即可
            res[queries[j][2]] = query(queries[j][0]);
        }
        
        return res;
    }
}

总时间复杂度 O ( n log ⁡ n + l q log ⁡ l q ) O(n\log n+l_q\log l_q) O(nlogn+lqloglq),每次询问时间 O ( 1 ) O(1) O(1)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/114055460