1707-与数组中元素的最大异或值

题目

1707. 与数组中元素的最大异或值 - 力扣(LeetCode) (leetcode-cn.com)

思路

该题目要求某个数字同数组中的数字异或的最大值,因此使用前缀树最为高效。如下题目也是使用前缀树来实现快速求解两个数最大异或值的,关于前缀树的构建和求解异或值最大的数的过程可以参考此博客。

421-数组中两个数的最大异或值_j5856004的博客-CSDN博客

如果不考虑本题目中查询请求中的最大数字限制,我们只需要将原数组的所有数加入到前缀树中,再使用上述题目中使用的搜索与n异或结果最大的数的算法即可求得最大的异或值。不过本题目加入了一个对搜索结果的的最大值的限制 (设其为limit),因此我们在前缀树中搜索的过程也有一些不同。

我们需要在前缀树的结点中加入一个min字段用于记录该节点对应的子树中存储的最小数字,根据min字段,我们就可以在搜索过程中确定是否需要搜索该子树(如果min > limit则不搜索该子树)。另外,在创建前缀树时,每插入一个数字也需要更新各个结点的min值。

在搜索过程中,对于数字numbit位为0时,我们首先尝试搜索前缀树结点的右子树,如果失败(没有找到结果,即右子树不存在/右子树结点min > limit),则尝试搜索左子树;对于数字numbit位为1时,我们首先尝试搜索前缀树结点的左子树,如果失败,则尝试所有右子树。

因为有min > limit的限制,因此上述搜索过程并不会完全遍历整个前缀树,对于没有合法结果的子树在访问一个结点后就不会继续向下搜索了。

代码实现


struct Tier{
    Tier* left;
    Tier* right;
    // 记录当前数存储的最小数字
    int min;
    Tier() {
        min = INT_MAX;
        left = nullptr;
        right = nullptr;
    }
};

class Solution {
public:
    vector<int> maximizeXor(vector<int>& nums, vector<vector<int>>& queries) {
        Tier* root = new Tier();
        vector<int> result(queries.size());
		
        // 将所有数字加入前缀树中
        for (int i : nums) {
            tier_add(root, i);
        }
		// 搜索每一个查询的结果
        for(int i=0; i<result.size(); i++) {
            result[i] = tier_find_max_with_limits(root, 0, queries[i][0], queries[i][1], 30);
            // 如果没有找到合适的数,则返回-1,不再与原数字异或
            if (result[i] != -1) {
                result[i] ^= queries[i][0];
            }
        }
        return result;
    }
	// 向前缀树中插入一个数字
    void tier_add(Tier* node, int num) {
        for(int i=30; i>-1; i--) {
            int c = (num >> i) & 0x1;
            // 更新当前树存储的最小数字
            if (num < node->min) {
                node->min = num;
            }
            if (c == 0) {
                if (node->left == nullptr) {
                    node->left = new Tier();
                }
                node = node->left;
            } else {
                if (node->right == nullptr) {
                    node->right = new Tier();
                }
                node = node->right;
            }
        }
        // 为最后一个结点添加最小值
        if (num < node->min) {
            node->min = num;
        }
    }
	/**
	 @param node   前缀树根结点,
	 @param prefix 当前已经确定的比特位(前30~bit位)
	 @param num    查找目标(找到一个数与num异或值最大)
	 @param limit  查找结果的最大值,即返回的结果需要<= limit
	 @param bit	   当前搜索的bit位(30 ~ 0), bit = -1表示搜索完成,找到结果
	 @ret          找到的与num异或值最大且<=limit的数
	 */
    int tier_find_max_with_limits(Tier* node, int prefix, int num, int limit, int bit) {
        int c_n;
        int tmp = -1;

        // node == nullptr或者node->min > limit(当前数存储的最小数字<limit)表示该路径没有合适的数
        if (node == nullptr || node->min > limit) {
            return -1;
        }

        //  bit == -1表示成功找到一个数,该数为prefix
        if (bit == -1) {
            return prefix;
        }
        
        // 其余情况则需要继续进行深度优先搜索
        c_n = (num >> bit) & 0x1;
		// 目标数第bit位为0
        if (c_n == 0) {
            // 尝试搜索前缀树中第bit位为1的数(使得异或结果最大化)
            tmp = tier_find_max_with_limits(node->right, prefix | (0x1 << bit), num, limit, bit - 1);
            // 没有结果则尝试搜索前缀树中第bit位为0的数
            if (tmp == - 1) {
                tmp = tier_find_max_with_limits(node->left, prefix, num, limit, bit - 1);
            }
        // 目标数第bit位为1
        } else {
            // 尝试搜索前缀树中第bit位为0的数(使得异或结果最大化)
            tmp = tier_find_max_with_limits(node->left, prefix, num, limit, bit - 1);
            // 没有结果则尝试搜索前缀树中第bit位为1的数
            if (tmp == -1) {
                tmp = tier_find_max_with_limits(node->right, prefix | (0x1 << bit), num, limit, bit - 1);
            }
        }
        // 返回搜索结果
        return tmp;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值