• 错误的集合


    这道题出自LeetCode,题目如下:

    集合 s 包含从 1n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复

    给定一个数组 nums 代表了集合 S 发生错误后的结果。

    请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

    示例 1:

    输入: nums = [1,2,2,4]
    输出: [2,3]

    示例 2:

    输入: nums = [1,1]
    输出: [1,2]

    这道题可以利用二进制位运算的性质巧妙解决。我们假设丢失的数字和重复的数字为a和b。由题目可知,我们有两个序列,一个序列A为[1,2,3,...,a,...,b,...,n],还有一个序列B为[1,2,3,...,b,b,...,n]。我们知道异或运算是满足相同为0不同为1的性质的,一个数异或它自身一定为0。因此,我们可以将两个序列合在一起求一次异或:

    A ^ B = a ^ b

    我们发现两个序列异或之后的结果就是我们要找的两个数字的异或。让我们再次回到异或的性质中来,两个数异或,相同的二进制位为0,不相同的二进制为1。由于a和b肯定是不相同,那么,a ^ b必定不为0,也就是说它存在一个为1的二进制位。我们假设a ^ b的结果为c。那么,让我们来寻找c最低的二进制为1的位:

    d = c & ~(c - 1)

    这个也比较好理解,我们假设c的二进制表示为x...x10...0,这里写出来的1就是它最低二进制位为1的位。那么,c - 1的二进制表示为x...x01...1,对其取反得到:~(x...x)10...0,我们可以发现1左边的高位数字一定是原先1左边的高位数字的取反,因此两者求与即可得到:d = 0...010...0,1就是要找的最低二进制为1的位。

    那么,有了这个之后,又能做什么呢?我们知道,这个d是可以区分开a和b的,即a和b中,一定有一个数对应的二进制位为0,另外一个为1。回到我们前面说的两个序列,这个d一定可以把两个序列进行划分,一边是二进制位为0的,一边是二进制位为1的,而且a和b一定位于两边。显然,如果这两边各自异或,最后剩下来的,一定一边是a,一边是b。

    有了a和b之后,我们需要弄明白哪个是重复的数字,哪个是缺失的数字。这个很简单,只需要遍历一遍包含重复数字的序列,就知道答案了。最后通过的代码如下:

    class Solution {
    public:
        vector<int> findErrorNums(vector<int>& nums) {
            int diff = 0;
            for(int i = 0; i < nums.size(); i++)
            {
                diff ^= (i + 1);
                diff ^= nums[i];
            }
    
            int pivot = diff & ~(diff - 1);
            int ga = 0, gb = 0;
    
            for(int i = 0; i < nums.size(); i++)
            {
                if((i + 1) & pivot)
                {
                    ga ^= (i + 1);
                }
                else
                {
                    gb ^= (i + 1);
                }
    
                if(nums[i] & pivot)
                {
                    ga ^= nums[i];
                }
                else
                {
                    gb ^= nums[i];
                }
            }
    
            vector<int> res;
            for(int i = 0; i < nums.size(); i++)
            {
                if(ga == nums[i])
                {
                    res = {ga, gb};
                    return res;
                }
            }
    
            res = {gb, ga};
            return res;
        }
    };
    
  • 相关阅读:
    软件架构设计模式简述
    [翻译]docker生态圈Mindmap
    完美解决Invalid layout of java.lang.String at value问题的方法
    用开源项目JazzyViewPager实现ViewPager切换动画
    用开源项目RangBar来实现有范围的SeekBar
    开源项目MultiChoiceAdapter详解(六)——GridView和MultiChoiceBaseAdapter配合使用
    开源项目MultiChoiceAdapter详解(五)——可扩展的MultiChoiceBaseAdapter
    开源项目MultiChoiceAdapter详解(四)——MultiChoiceBaseAdapter的使用
    开源项目MultiChoiceAdapter详解(三)——MulitChoiceNormalArrayAdapter的使用
    开源项目MultiChoiceAdapter详解(二)——MultiChoiceArrayAdapter的使用
  • 原文地址:https://www.cnblogs.com/back-to-the-past/p/14828061.html
Copyright © 2020-2023  润新知