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

Posted 捕获一只小肚皮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你真的会 &与运算妙用吗?相关的知识,希望对你有一定的参考价值。

求取多少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; 
}

以上是关于你真的会 &与运算妙用吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python这些位运算的妙用,绝对让你大开眼界

js中 && 与 || 的妙用

关于js代码中与或运算符||&&的妙用

&&和||的操作符妙用(javascript)

关于setTimeout的妙用

三目(元)运算符的 前台 应用,妙用!!!