你真的会 &与运算妙用吗?

6 篇文章 0 订阅
本文介绍了位操作在编程中的几个高级技巧,包括利用n&(n-1)计算二进制中1的个数,判断是否为2的次方,以及找出二进制中最低位的1。通过实例和代码解释了这些技巧的原理和应用场景,并提供了用于统计两个整数二进制中不同位的个数的方法。此外,还讨论了n&1判断奇偶性和n&(-n)获取最低位1的用途。
摘要由CSDN通过智能技术生成

求取多少1

输入一个整数,求该整数二进制格式有多少位是1

输入: 22

输出: 3

输入:251

输出:7

运用原理: n & (n-1)

比如: 16 与 16-1

  • 10000(二进制16)
  • 01111(二进制15)

16&15 的结果就是0. 发现什么了?? 抵消了数字16二进制的倒数第一个1.

下面我们以251画图演变:

image-20210520223244693

  • 其实减1的作用就是为了让二进制最后一个1的后面全部为0,利于相&计算.

上代码:

#include <stdio.h>
int main()
{
    int n = 0,count = 0;
    scanf("%d", &n);
    while(n)
    {
        n = n&(n-1);
        count++;
    }
    printf("该数字有%d个1",count);
    return 0;
}


再来个进阶版 & 运算

输入一个整数n,判断n是不是2的次方. 是输出1,否则输出0

输入:16

输出:1

输入:9

输出:0

输入:32

输出:1

原理:还是 n&(n-1)

记得上面那个题我说的n-1的作用是什么吗? 把二进制中的最后一个1的后面全部变为0.

比如1000(十进制8) - 1 = 0111;

而2进制的每位的权重就是2的次方,比如1011换算成十进制 1x2³ + 0x2² + 1x2¹ + 1x2º = 11

所以2的次方的二进制只能有一个1,且在最高位,比如:

  • 10000 (2的4次方 16)
  • 100000(2的5次方 32)

那么只要 n&(n-1)的结果是0,就说明n是2的次方

#include <stdio.h>
int main()
{
    int n = 0;
    scanf("%d", &n);
    int ret = 0;
    
    ret = (n & (n - 1)) == 0 ? 1 : 0;   //博主运用的条件表达式,大家也可以用if判断
    
    printf("%d\n", ret);
    return 0;
}


更高级进阶

输入两个整数,求两个整数二进制中相同位置不同数字的位置有多少个?

输入: 22 33

输出: 5

输入:1999 2299

输出:7

解析:

题目要求的是求相同位置不同数字的位置数量,那我们是不是可以把相同的数字全部转化为0??(用 ^ 或运算)

剩下的就是不同的数字了,然后就是消去 1 .用 n&(n-1)

以22 33为例. 请看图:

image-20210520230624351

而统计多少个1,不就是最开始那个题吗?

#include <stdio.h>
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int ret = n ^ m;
    int count = 0;
    while(ret)
    {
        ret = ret&(ret - 1);
        count++;
    }
    printf("不同的位有%d个", count);
    return 0;
}

倒数第二个小技巧 n&1

那么大家猜猜 这个用来干嘛的?对,判断整数n是不是奇偶
原理:

  • 奇数的二进制末尾一定是1
  • 偶数的二进制末尾一定是0
    而1的二进制是00000000001等,前面全是0,也就是说一个数与1进行&运算,实际运算的只有1位,那就是末位数字0或1(仔细去想想是不是).

所以,如果 n&1为真,就是奇数
否则偶数

最后一个小技巧 n&(-n)

这个技巧我们是用来 寻找该数字的最低位为1的某个二进制.
比如有这样一个二进制数
1001101011100000
他的最低位1的位置在倒数第六个,即我们需要找下面这个数字
0000000000100000
就可以用上面的 n = n&(-n)技巧,最后n就是最低位的1.

总结: n&(n-1) **** n&1 ***** n&(-n) 技巧的综合 需要结合 ^异或运算技巧

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* singleNumber(int* nums, int numsSize, int* returnSize){
    int *p = (int*)malloc(8);
    int i = 0,a = 0,b =0;
    long ret = 0;

    //最终异或值
    for(i = 0;i<numsSize;i++)
    {
        ret^=nums[i];
    }
    //寻找最低位的1
    ret = ret&(-ret);

   //分组运算
    for(i = 0;i<numsSize;i++)
    {
        if(ret & nums[i])
        {
            a ^= nums[i];
        }
        else{
            b^=nums[i];
        }
    }
    p[0] = a;
    p[1] = b;
    *returnSize = 2;
    return p; 
}
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

捕获一只小肚皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值