“借题发挥“的二进制解析

二进制提取位及各种运算

牛客链接
以上是求二进制的一道题,可以点击了解后再继续阅读

一.求"1"的个数

提供以下几种解题思路,并作比较

思路一:

循环进行以下操作,直到n被缩减为0:

  1. 用该数据模2,检测其是否能够被2整除
  2. 如果可以:则该数据对应二进制比特位的最低位一定是0,否则是1,如果是1给计数加1
  3. 如果n不等于0时,继续1
    在这里插入图片描述代码如下:
int count_one_bit(int n)
{
	int count = 0;
	while(n)//判断是否为0,即为终止条件
	{
		if(n%2==1)//判断最低位是否为1,奇偶思想
			count++;//如果为1,计数器加一
		n = n/2;//这就是让高位依次到最低位
	}
	return count;
}

上述方法缺陷:进行了大量的取模以及除法运算,取模和除法运算的效率本来就比较低。

思路二:

方法二思路:
一个int类型的数据,对应的二进制一共有32个比特位,可以采用位运算的方式
在这里插入图片描述

int count_one_bit(unsigned int n)
{
	int count = 0;
	int i = 0;
	for(i=0; i<32; i++)
	{
		if(((n>>i)&1) == 1)
			count++;
	}
	return count;
}

方法二优点:用位操作代替取模和除法运算,效率稍微比较高
缺陷:不论是什么数据,循环都要执行32次
再改进:
在这里插入图片描述

int forBinarynum(int n){
  int result = 0;
  while( n ){
    result += (n & 1);
    n = (n >> 1);
  }
  return result;
}

你以为这就结束了吗?不是的,以上的方法你只要在牛客网上实验,就会显示
在这里插入图片描述

思路3:

思路:采用相邻的两个数据进行按位与运算
举例:
9999:‭10 0111 0000 1111‬
第一次循环:n=9999 n=n&(n-1)=9999&9998= 9998
第二次循环:n=9998 n=n&(n-1)=9998&9997= 9996
第三次循环:n=9996 n=n&(n-1)=9996&9995= 9992
第四次循环:n=9992 n=n&(n-1)=9992&9991= 9984
第五次循环:n=9984 n=n&(n-1)=9984&9983= 9728
第六次循环:n=9728 n=n&(n-1)=9728&9727= 9216
第七次循环:n=9216 n=n&(n-1)=9216&9215= 8192
第八次循环:n=8192 n=n&(n-1)=8192&8191= 0
可以观察下:此种方式,数据的二进制比特位中有几个1,循环就循环几次,而且中间采用了位运算,处理起来比较高效
图片以100为例

代码如下:

int count_one_bit(int n)
{
   int count = 0;
   while(n)
   {
   	n = n&(n-1);
   	count++;
   }
   return count;
}

在这里插入图片描述这个题解充分说明:造成两种结果,一种是通过不了,另一种是可以通过的.

原因是,要考虑的一个问题就是,关于1在高低位问题,关于高低位问题注意大小端,.点击可以详细了解.

在采用小端情况下,如果1几乎在低位,也就是大家习惯的二进制展开后左面部分,这就需要做很多次移位运算,所以考虑要全面,而对于无论1在高位还是低位,循环次数只取决于1的个数,具体原理上文已经解释过了.

如:0111 1111 1111 0000 0000 0000 0000 0000,前面几种方式需要移位,并且判断31次,而最后一种方法只需要移位运算且判断11次即可,一比较就很明显.

二.求两个整数二进制格式有多少个位不同

思路:

  1. 先将m和n进行按位异或,此时m和n相同的二进制比特位清零,不同的二进制比特位为1
  2. 统计异或完成后结果的二进制比特位中有多少个1即可
    例子如下
    在这里插入图片描述代码如下:
#include<stdio.h>
int count_one_bit(int n)
{
	int count = 0;
	while(n)
	{
		n = n&(n-1);
		count++;
	}
	return count;
}
int forFinalBinary(int m , int n){
  int result  = 0;
  result = (m ^ n);
return result;
}
int main(){
    int n = 0;
    int m = 0;
    scanf("%d %d",&n,&m);
 printf("%d\n",count_one_bit(forFinalBinary(n,m)));
 return 0;
}

在这里插入图片描述
运行结果如上,解决

三.打印整数二进制的奇数位和偶数位(获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列)

思路如下:

  1. 提取所有的奇数位,如果该位是1,输出1,是0则输出0
  2. 以同样的方式提取偶数位置

检测num中某一位是0还是1的方式:

  1. 将num向右移动i位
  2. 将移完位之后的结果与1按位与,如果:
    结果是0,则第i个比特位是0
    结果是非0,则第i个比特位是1
    在这里插入图片描述

代码如下:

void Printbit(int num)
{
	for(int i=31; i>=1; i-=2)
	{
		printf("%d ", (num>>i)&1);
	}
	printf("\n");
    
	for(int i=30; i>=0; i-=2)
	{
		printf("%d ", (num>>i)&1);
	}
	printf("\n");
}

小结:

  1. 关于位运算的优点,题中详细体现了
  2. 就是关于运算思想的积累,如何了解最优解,再去学习,掌握,最优解不是一蹴而就的
  3. 本文没有详细介绍大小端存储,可以详细了解一下

不足之处欢迎指点,感谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值