《五月集训》(第十天)——位运算

前言

        欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
        今天是五月集训第十天:位运算

一、练习题目

        191. 位1的个数
        461. 汉明距离
        136. 只出现一次的数字
        137. 只出现一次的数字 II

二、算法思路

  • 1、191. 位1的个数:位运算,这题目用到了&与运算和>>右移运算。& 1相当于模2也可以用来判断奇偶数,>> 1相当于除2。
  • 2、461. 汉明距离:用了第一题的函数,对于两个数,如果二进制位相同,则汉明距离位0,不同则为1,这就是异或^运算了,巧妙运用异或解决。
  • 3、136. 只出现一次的数字:利用异或^,因为重复的出现的是偶数,偶数个异或还是0,最后异或上唯一一个出现的数,就是它本身。(异或满足交换律和结合律。)
  • 4、137. 只出现一次的数字 II:这道题需要一个巧妙的处理,参考了大佬们的思路。对于某个重复出出现三次的数,在不考虑进位的情况下,它对每一位二进制位的贡献是3或者0,只出现一次对每一位二进位的贡献要么是1要么是0,当我们把所有数字的每一位二进制加起来,不考虑进位的情况它的和要么是 3 n + 1 3n+1 3n+1,要么是 3 n 3n 3n,语言有点难懂,举个例子:
[1,1,1,3]
各个位置二进制的情况如下:
 0 0 1
 0 0 1
 0 0 1
 0 1 1
各个二进制位置求和:
 0 1 4 (3 + 1) 

规律就出来了,对每一位二进制位求和后对3取模,取模的结果是1或者0,如果是1对应着唯一出现一次的数在该位置上也是1,0的话就说明是0,然后把这个数还原出来。还是上面的例子唯一出现的数字是3,在第一个二进制位取模是1,第二个二进制取模也是1,第三个是0,再做一步 1 ∗ 2 0 + 1 ∗ 2 1 + 0 ∗ 2 2 = 3 1*2^0+1*2^1+0*2^2 = 3 120+121+022=3这题目可以引申出,很多重复四次、五次、六次让你找唯一出现的数,道路是一样的对4、5或者6取模。

三、源码剖析

// 191. 位1的个数
class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ans = 0;
        while(n) {
            ans += (n & 1); //(1)
            n >>= 1; //(2)
        }
        return ans;
    }
};
  • 1、例如:8的二进制1000,用n&1判断末尾是不是1是的话计数器加1否则加0。
  • 2、然后把n右移一位,二进制右移动左边补零的,如0100这是8右移一位后的结果,这样最后就会变成0
// 461. 汉明距离
class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ans = 0;
        while(n) {
            ans += (n & 1);
            n >>= 1;
        }
        return ans;
    } //(1)

    int hammingDistance(int x, int y) {
        return hammingWeight(x ^ y); //(2)
    }
};
  • 1、191题学以致用,用了它的函数;
  • 2、分析题意转换成两数异或后求位1的个数。
// 136. 只出现一次的数字
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int n = nums.size(), ans = 0;
        for(int i = 0; i < n; i++) {
            ans ^= nums[i]; //(1)
        }
        return ans;
    }
};
  • 1、偶数个重复最终是0,0异或唯一的数就是它本身。
// 137. 只出现一次的数字 II
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        for(int i = 0; i < 32; i++) {
            int tmp = 0;
            for(auto n : nums) {
                tmp += (n>>i) & 1;
            } //(1)

            tmp %= 3; //(2)
            if(tmp) {
                ans += (1<<i); //(3)
            }
        }
        return ans;
    }
};
  • 1、逐个二进制位求和;
  • 2、对每个二进制位对3取模
  • 3、将我们要找的数对应二进制位置置1或0,详情可看算法思路。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值