LeetCode 数组中两个数的最大异或值(建树+贪心策略)

给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。

找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。

你能在O(n)的时间解决这个问题吗?

示例:

输入: [3, 10, 5, 25, 2, 8]
输出: 28
解释: 最大的结果是 5 ^ 25 = 28.

思路分析:这种题就不要暴力法,指名道姓说要O(n)。根据提示需要使用建树。
首先我们需要知道,二进制高位为1会大于低位的所有和,比如"11111111"最高位代表的"1"按权展开为128,而后面的“1111111”按权展开的和也只是127。所以进行异或时应该尽量选择高位异或结果为“1”的。
第一步:遍历数组,我们按照二进制[31,30,…,1, 0]各位的状态进行建树,left放置0,right放置1。比如某个int型数的二进制是"0110110…",我们需要将其放置到[left,right,right,left,right,right,left…]。
第二步:遍历数组,按照贪心策略,尽量维持当前选择的方向能保证当前能位异或结果为1。

class Solution {
public:
    struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
    int findMaximumXOR(vector<int>& nums) {
        TreeNode *root = new TreeNode(-1);
        int maxRes = 0;
        //建立二叉树
        for (auto num : nums){
            TreeNode *treePtr = root;
            //按照[31,30, .... 1,0]二进制数字串的位位0、1进行区别,1放左边,0放右边
            //从高位向低位逐渐检测,递归寻找放的位置
            for (int i = 31; i >= 0; --i){
                if ((num & (1 << i)) == 0){
                    //num的第i位为0,需要放到当前节点的left
                    if (treePtr->left == NULL){
                        treePtr->left = new TreeNode(0);
                    }
                    treePtr = treePtr->left;//转移到left,进行i + 1的放置
                }
                else{
                    //num的第i位为1,需要放到当前节点的right
                    if (treePtr->right == NULL){
                        treePtr->right = new TreeNode(1);
                    }
                    treePtr = treePtr->right;//转移到right,进行i + 1的放置
                }
            }
            //最后放在底部节点的left位置
            treePtr->left = new TreeNode(num);
        }
        //搜索
        for (auto num : nums){
            TreeNode *treePtr = root;
            //从高位向低位寻找,贪心策略,尽量保持当前位异或为1
            for (int i = 31; i >= 0; --i){
                if ((num & (1 << i)) == 0){
                    //如果num的第i位0,则应该优先选择right,因为right为1,这样1 ^ 0 == 1
                    if (treePtr->right != NULL){
                        treePtr = treePtr->right;
                    }
                    else{
                        treePtr = treePtr->left;
                    }
                }
                else{
                    //如果此位是1,则应该优先选择left
                    if (treePtr->left != NULL){
                        treePtr = treePtr->left;
                    }
                    else{
                        treePtr = treePtr->right;
                    }
                }
            }
            //最后去底端的left进行异或操作
            maxRes = max(maxRes, treePtr->left->val ^ num);
        }
        return maxRes;
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/88756998