leetcode“位运算”——只出现一次的数字

只出现一次的数字i: 

https://leetcode.cn/problems/single-number/

给你一个非空整数数组 nums,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现一次的元素。 

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int j=0;
        for(auto i:nums)
        {
            j^=i;
        }
        return j;

    }
};

 这道题其实告诉你有两个重复出现的数,就在提示你用异或了,用0依次与其他数异或,最后出现两次的都被消掉了,最后剩下的数就是只出现一次的数。

只出现一次的数字 ii:

https://leetcode.cn/problems/single-number-ii/

 给你一个整数数组 nums,除某个元素仅出现 一次外,其余每个元素都恰出现 三次。请你找出并
返回那个只出现了一次的元素。

 第一部分:因为每个数是32位,我们把每个数的每一位分别放进一个数组,去统计每一位所有出现1的次数。1<<i 的意思是为了探测每一位的1出现的次数。将那个值与(1<<i)进行“与”运算,只要那一位是1,条件为真,将代表这一位的个数的数组进行加1。反复遍历,直到所有都遍历完为止。

第二部分:看每一位是否是3*N+1还是3*N+1,因为3*N+1代表那个要找的数这一位是1,3*N代表0,然后我们再定义一个变量num=0,如果是3*N+1,则将num与(1<<i)进行“或”运算,知道遍历完所有的,num就是我们要找的数了。

记住探测某1位是0还是1,用“与”运算。使某1位变成1,用“或”运算。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int v[32] = {0};
        for (auto val : nums) {
            for (int i = 0; i < 32; i++) {
                if (val & (1 << i)) {
                    v[i]++;
                }
            }
        }
        int num = 0;
        for (int i = 0; i < 32; i++) {
            if (v[i] % 3 == 1) {
                num |= (1 << i);
            }
        }
        return num;
    }
    
};

 只出现一次的数字iii:

 https://leetcode.cn/problems/single-number-iii/

 给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案

首先,定义一个变量val=0,然后将nums的所有的数与val,依次“异或”运算,因为出现两次的数在异或的过程中,都被消除了。所以val的值是唯一出现一次的两个数相互异或的结果。

那么val(相互异或的结果),对这道题目起了什么作用呢?

我们可以把val的32位,一位一位分析,“异或”的原理是——相同为0,相异为1。所以我们接下来就要把val的值一位一位来看,从第0位开始看,依次寻找第一次出现1的位是在哪,1代表两个值相异。

第二步,是为了找到第一个为“1”的位的位置。

第三步:我们正好可以将第二步找到的位置,与(1<<i)进行“与”运算,将这个的结果作为分类的条件,然后分成两类,依次遍历nums的每一个元素,如果 e & (1<<i) 的结果为非0,那么就与第一类的数依次“异或”运算,否则与第二类“异或”运算。因为重复出现的会被消掉,所以num1 和num2 就是我们要找的两个只出现一次的数。

第四步,将这两个插入新定义的vector v中,然后返回 v 即可。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
       //第一步:
        int val=0;
        for(auto e:nums)
        {
            val^=e;
        }
       //第二步:
        size_t i=0;
        for(i=0;i<32;i++)
        {
            if(val & (1<<i))
            {
                break;
            }
        }
       //第三步:
        int num1=0,num2=0;
        for(auto e:nums)
        {
            if(e & (1<<i))
            {
                num1^=e;
            }
            else
            {
                num2^=e;
            }
        }
        //第四步:
        vector<int> v;
        v.push_back(num1);
        v.push_back(num2);
        return v;
    }
};

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值