【LeetCode】【剑指offer】【数组中数字出现的次数(一)】

发布于:2023-01-09 ⋅ 阅读:(467) ⋅ 点赞:(0)

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:

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

限制:

2 <= nums.length <= 10000

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

第一种方法就是采用我们的map映射,先统计全部的元素的出现次数,然后将出现次数为1的数据封装到一个vector中并且返回这个容器

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        map<int ,int> record;
        vector<int> result;
        for(auto num:nums)
        {
            record[num]++;
        }
        for(auto num:nums)
        {
            if(record[num]==1)
            {
                result.push_back(num);
            }
        }
        return result;
    }
};

 

但是上面这种算法的效率非常低下,所以我们采用下面这种方法。 

我们可以采用分组按位与的策略。也就是说:

我们首先将全部的元素都异或与到一起。(按位与的特性就是相同的元素异或到一起的话就会抵消)

所以这时候我们其实得到的是那两个落单的数字的异或的结果

然后我们从右往左,找到这个异或结果的第一个1,我们这里简称为x位。

为什么要找这个第一个1呢?

因为1的形成只可能是0和1进行异或。也就是说这两个数字中的其中一个这一位一定是1。(这两个数字不同导致异或的结果中一定有1存在)

然后我们将全部的数据分成两组,一组是当前这个x位的位置为1的组,另一组是当前这个x位为0的组。两组分别异或,就能分别从这两组中得到我们想要的结果。

假设数据的初始是

1

3

3

5

001

011

011

101

我们将全部的数据都异或(不相同为1,相同为0)到一起,得到100,
我们观察发现是从右往左第三位为1,所以我们将原来的数据分成两组,一组是二进制从右往左第三位是1的,另一组是从右往左第三位是0的
所以我们的1,3,3是一类,5是另外一类

 然后我们分别将每一组数据进行异或操作,1,3,3异或得到的结果是1(异或会将相同的元素抵消掉),另一组是5,这样我们就找到了这两个落单的数据1,5.

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int result=0;
        //将我们全部的数据都异或到一起
        for(auto num:nums)
        {
            result^=num;
        }
        //找到从右往左的第一个1的位置
        int point=1;
        while((point&result)==0)
        {
            point=point<<1;
        }
        //分组获取我们的两个落单的数据
        int result_1=0;
        int result_2=0;
        for(auto num:nums)
        {
            //如果这个数据和我们上面取得的第一个1的位置按位与是0,就将其归为一类
            if((point&num)==0)
            {
                result_1^=num;
            }
            //如果这个数据和我们上面取得的第一个1的位置按位与是point(1×2^n),就将其归为另一类
            else
            {
                result_2^=num;
            }
        }
        //两组数据异或之后,相同的元素会被抵消,不相同的元素会留下
        //我们将我们上面获取到的结果封装到一个容器中,并将这个容器返回。
        vector<int> final;
        final.push_back(result_1);
        final.push_back(result_2);
        return final;
    }
};


网站公告

今日签到

点亮在社区的每一天
去签到