你真的会 &与运算妙用吗?
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画图演变:
- 其实减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为例. 请看图:
而统计多少个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;
}
以上是关于你真的会 &与运算妙用吗?的主要内容,如果未能解决你的问题,请参考以下文章