微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

与数组中的元素的最大异或|力码

如何解决与数组中的元素的最大异或|力码

我在 Leetcode 上练习时遇到了这个问题。

问题陈述 (link):

You are given an array nums consisting of non-negative integers. 
You are also given a queries array,where queries[i] = [xi,mi].

The answer to the ith query is the maximum bitwise XOR value of xi and any element of nums that does not exceed mi. 
In other words,the answer is max(nums[j] XOR xi) for all j such that nums[j] <= mi. 
If all elements in nums are larger than mi,then the answer is -1.

Return an integer array answer where answer.length == queries.length and answer[i] is the answer to the ith query.

约束:

1 <= nums.length,queries.length <= 10^5
queries[i].length == 2
0 <= nums[j],xi,mi <= 10^9

我使用trie方法解决了这个问题,然后去讨论部分查看其他人的解决方案。在那里,我遇到了这个解决方案 (link):

class Solution {
public:
    vector<int> maximizeXor(vector<int>& nums,vector<vector<int>>& queries) {
        const int n = nums.size(),q = queries.size();
        vector<int> ans(q,-1);
        sort(nums.begin(),nums.end());
        
        for (int i = 0; i < q; i++) {
            const int x = queries[i][0],m = queries[i][1];
            if (m < nums[0]) continue;
            
            int end = upper_bound(nums.begin(),nums.end(),m) - nums.begin();
            int start = 0;
            
            int k = 0,cur = 0;
            for (int bit = 31; bit >= 0; bit--) {
                if (x & (1 << bit)) { // hope A[i] this bit == 0
                    if (!(nums[start] & (1 << bit))) {
                        k |= 1 << bit;
                        end = lower_bound(nums.begin() + start,nums.begin() + end,cur | (1 << bit)) - nums.begin();
                    } else {
                        cur |= 1 << bit;
                    }
                } else { // hope: A[i] this bit == 1
                    if (start <= end - 1 && (nums[end - 1] & (1 << bit))) {
                        k |= 1 << bit;
                        cur |= 1 << bit;
                        start = lower_bound(nums.begin() + start,cur) - nums.begin();
                    }
                }
            }
            ans[i] = k;
        }
        return ans;
    }
};

不幸的是,我无法理解此解决方案。如果有人能对此解决方案给出适当的解释(主要是在遍历位时),我将不胜感激。

解决方法

此实现存在一些问题。 startend 应该仍然是迭代器,它们可以直接使用而无需一直添加/减去 nums.begin()。我们谈论的是非负整数,所以只要它们适合正常的 int 第一位无论如何都是 0,所以我们应该从 int bit = 30 开始跳过一次不必要的迭代。对于整数和迭代器,start <= end - 1start < end 更好。代码由一个函数组成,那么绝对不需要类,所以应该更喜欢命名空间。应用这些更改后,代码将如下所示:

namespace Solution
{

// as EXACTLY two values,std::pair is more appropriate
// we are not modifying queries,so should be accepted as const
std::vector<int> maximizeXor
(
    std::vector<int>& nums,std::vector<std::pair<int,int>>const& queries
)
{
    const int q = queries.size();
    std::vector<int> ans(q,-1);
    sort(nums.begin(),nums.end());
    // remove duplicates:
    // -> less numbers to iterate over
    nums.erase(unique(nums.begin(),nums.end()),nums.end());

    for (int i = 0; i < q; ++i)
    {
        int const x = queries[i].first,m = queries[i].second;
        // we have a sorted array,remember?
        // if first value is larger than the query maximum,then there are no
        // corresponding numbers – and as the vector is initialised to -1 
        // anyway,the appropriate value is there already so we can simply skip
        if (m < nums[0])
        {
            continue;
        }

        // using iterators pointing at the appropriate indices
        auto end = upper_bound(nums.begin(),nums.end(),m);
        auto start = nums.begin();

        int /*k = 0,*/ cur = 0;

        // intention is to check each bit of x

        // modifying the loop!
        //for (int bit = 30; bit >= 0; bit--)
        int const MaxBit = 1 << sizeof(int) * CHAR_BIT - 2;
        for (int bit = MaxBit; start != prev(end); bit >>= 1)
        {
            // OK; fixing an issue and adding some tricks to handle the loop
            // a bit cleverer...

            // sizeof(int) * CHAR_BIT: int is NOT guaranteed to have exactly 
            // 32 bits! if you want to be on the safe side,either calculate 
            // as above or use int32_t instead

            // changed abort condition:
            // I modified the algorithm slightly such that we can break early
            // unique'ing the vector allows us to drop the original
            // condition bit >= 0 entirely,this will be explained later

            // I store the bit-MASK in bit now,now we do not have to 
            // calculate it again and again (1 << bit)

            if (x & bit)
            {
                // so x has a 1-bit at bit index 'bit'

                // in the range yet to be considered we have two groups of
                // numbers:
                // 1. those having a 0-bit at bit-index 'bit'
                // 2. those having a 1-bit

                // if we compare single bits,we get:
                // x   = *1***
                // num = *0*** XOR: *1***
                // num = *1*** XOR: *0***

                // IF now there are numbers with a zero bit at all,then one 
                // of these will produce the maximum,whereas those with a 
                // 1-bit cannot asnumbers are sorted,we can just check very
                // first value of the range:


                // any number having a 1-bit at the same bit index will produce 
                // a zero-bit – thus these numbers CANNOT produce the maximum

                if (!(*start & bit))
                {
                    // bits differ,remember?
                    // thus the XOR will have a one-bit we store right now
                    // actually,we do NOT need that,we can handle that cleverer
                    //k |= 1 << bit;
                    // instead,I handle this with the NEW loop condition

                    // fine – there ARE numbers with zero-bits,so remove all
                    // numbers with 1-bit from range; as they all are at the end
                    // of,we simply move this one towards front:
                    end = lower_bound(start,end,cur | bit);
                    // cur contains those bits of the number producing the 
                    // maximum that have been evaluated so far,it is a 
                    // lower bound for – we do NOT modify it,but we can
                    // calculate a new upper bound from!
                }
                else
                {
                    // well,there is no such number with a 0-bit
                    // we cannot move end or start position
                    cur |= bit;
                }
            }
            else
            {
                // analogously:
                // x   = *0***
                // num = *0*** XOR: *0***
                // num = *1*** XOR: *1***

                // so all members having a 1-bit are of interest  – IF there 
                // are – and we can skip those numbers with 0-bit at the
                // beginning

                // if there are,then they are at the very end
                // 'end' iterator points to one past,so we need predecessor
                if (/*start < end &&*/ *prev(end) & bit)
                {
                    // first condition is handled in the loop now

                    // as above: we can handle that cleverer
                    //k |= 1 << bit;

                    // now current mask NEEDS the one-bit
                    cur |= bit;
                    start = lower_bound(start,cur);
                }
            }
            // with unchanged loop it was not possible to break early as k still
            // needed to be calculated
            //ans[i] = k;

            // with or without early break,we can always:
            ans[i] = *start ^ x;
            // with every iteration,we extend the bit mask 'cur' the numbers 
            // have to match with by one bit (either the 0 gets confirmed
            // or replaced by a 1). 
            // After 31 iterations (sign bit is ignored as we only have 
            // positive integers),*all* bits are defined (if we had omitted 
            // the early breaks we could have calculated
            // ans[i] = cur ^ x; as well...).

            // so all numbers that yet might have remained in the valid range
            // must match this pattern,i. e. be equal. However as unique-ing,// there is exactly one single value left...
        }
    }
    return ans;
}
} // namespace Solution

请注意,std::lower_bound 具有(提供随机访问迭代器,与 std::vector 一样)的复杂度为 O(log(n)),因此执行单个查询具有 O(log(n)) 和 {{ 1}} 是数字的数量。加上排序和查询 n 次的开销,与复杂度为 O(m*n) 的“原始”迭代相比,我们得到的总复杂度为 m。如果 O(n*log(n) + m*log(n)) = O((n+m)*log(n))m 具有相似的幅度或更大,则我们具有复杂性优势(已经在原始变体中,我的调整只是稍微调整常量,但不会改变复杂性)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。