解题 -- 有关二进制的题型总结

前言

路漫漫其修远兮,吾将上下而求索;


例一、

牛客网链接:小乐乐改数字_牛客题霸_牛客网小乐乐喜欢数字,尤其喜欢0和1。他现在得到了一个数,想把每位的数变成0或1。如果某一位是奇。题目来自【牛客题霸】http://www.nowcoder.com/practice/fcd30aac9c4f4028b23919a0c649824d

思路:首先是需要得到这个十进制数据的每一位,对得到的每一位上的数值判断奇偶,然后转换成对应的0或者1;倘若这个数的每一位均是偶数,那么每一位都会变成0,即整体为0;在高位的0可以省略:

代码如下:

//小乐乐改动数字
int main()
{
	//输入
	int input = 0;
	scanf("%d", &input);
	int sum = 0;//整合为一个数
	int count = 0;//记录数的位
	int ret = 0;//记录每一位的数字

	while (input)
	{
		ret = input % 10;//得到每一位
		if (ret % 2 == 0)//偶数
			ret = 2;
		else//奇数
			ret = 1;
		sum += ret * pow(10, count);

		//调整
		input /= 10;
	}
	printf("%d\n", sum);

	return 0;
}

为什么循环结束的标志是 input == 0?

  • 当input 只有一位的时候,也是需要对其”位“上的数字进行奇偶判断的,在循环之中input %10 可以得到这一位的数字,而 intput /= 10  每执行一次去掉一位的数;即 intput /= 10  是在调整位数;想要得到对应位上的数字,有多少位,便要使用相应次数的  input %10 与 intput /= 10;而当input /10 为 0时,代表input 为个位数,仅需执行一次循环中的代码便可;故而while 的判断条件为input == 0;

例二、

题目:输入一个整数(int 类型的数据) ,并计算统计其二进制数中1 的个数

思路一:联想到得到十进制数的每一位:通过 %10 与 /10 ;同理,对于二进制数来说,%2 与 /2 也可以得到对应的二进制位,然后再与1作比较即可;

代码如下:

//思路一
int NumberOfBinary1_1(unsigned int input)
{
	int count = 0;
	while (input)
	{
		if (input % 2 == 1)
			count++;
		//调整
		input /= 2;
	}
	return count;
}

int main()
{
	unsigned int input = 0;
	scanf("%d", &input);
	int count = NumberOfBinary1_1(input);

	return 0;
}

思路二:

从低位开始找:

利用 右移操作符 >> 得到二进制位中的每一位,然后与1按位与&,利用& 的特性,二进制位上有0变为0,全一才为1

代码如下:

//思路二
int NumberOfBinary1_2(unsigned int input)
{
	//得到每一个二进制位
	int count = 0;
	int i = 0;
	for (i = 0; i < 32; i++)//循环32次
	{
		if ((input >> i) & 1 == 1)
			count++;
	}
	return count;
}

int main()
{
	unsigned int input = 0;
	scanf("%d", &input);
	int count = NumberOfBinary1_2(input);

	return 0;
}

思路三:

高位开始找:

二进制中的每一位数据代表着2的多少次方,倘若1000 与 0111 按位与的话,其结果变为0;一个2^0 到2^(n-1) 之间的数求和,即等差数列求和,其第一项为1,倍数为2,其和为2^n-1 ; 显然,1000对应的十进制数字为8,0111对应的十进制数字为 7 ;

按位与& 的特点是:有0为0,全1才为1;当一个二进制序列与(二进制序列 - 1)按位与 之后势必会丢失一个高位;而低位中的1在进行按位与& 的时候并不会对原数二进制位上除最高位以外的位的数据造成影响;那么除掉了多少个二进制位便代表着有该二进制序列中有多少个1;

代码如下:

//思路三
int NumberOfBinary1_3(unsigned int input)
{
	int count = 0;
	while (input)
	{
		input = (input - 1) & input;
		count++;
	}
	return count;
}

int main()
{
	unsigned int input = 0;
	scanf("%d", &input);
	int count = NumberOfBinary1_3(input);

	return 0;
}

例三、

题目:打印整数(int 类型的数据) 二进制的奇数位和偶数位

注:此处认为二进制位的最低位为0位;

思路:得到二进制位的奇数位与偶数位,不难想到使用for 循环i 逐渐递增,配合右移操作符 >> ,然后再分别打印

 代码如下:

 //打印整数二进制的奇数位和偶数位
 void PrintBinary(int n)
 {
	 int i = 0;
	 printf("二进制的奇数位:");
	 for (i = 30; i>=0; i -= 2)//奇数位
	 {
		 printf("%d ", (n >> i)&1);//有0为0,全1才为1
	 }
	 printf("\n二进制的偶数位:");
	 for (i = 31; i>0; i -= 2)
	 {
		 printf("%d ", (n >> i) & 1);
	 }
 }

int main()
{
	PrintBinary(118);

	return 0;
}

例四、

题目求两个数(int 类型的数据) m、n的二进制位表达式之中,有多少比特位不同;

思路一:

创建一个计数器count , 然后再分别取得m、n 的二进制位进行比较,不相同便count++;

代码如下:

 //思路一
 int calc_diff_bit_1(int m , int n)
 {
	 //计数器
	 int count = 0;
	 //分别比较m n中的二进制位
	 for (int i = 0; i < 32; i++)
	 {
		 if (((m >> i) & 1) != ((n >> i) & 1))
			 count++;
	 }
	 return count;
 }

int main()
{
	int ret = calc_diff_bit_1(118, 40);
	printf("%d\n", ret);

	return 0;
}

思路二

回顾之前学习的操作符,按位异或^ 的功能: 相同为0,相异为1

于是乎便可以先让m 与n 按位异或,然后求所得结果中的 1  的个数,便是不同比特位的个数;(求一个二进制序列之中1的个数,例二中列举出了三种方法);

代码如下:


 //思路二
 int calc_diff_bit_2(int m, int n)
 {
	 int ret = m ^ n;//相同位0,相异位1
	 //此处采用例二中的第三种方法来计算二进制序列中1的个数
	 int count = 0;
	 while (ret)
	 {
		 ret = ret & (ret - 1);
		 count++;
	 }
	 return count;
 }

int main()
{
	int ret = calc_diff_bit_1(118, 40);
	printf("%d\n", ret);

	return 0;
}

例五、

题目:交换奇偶位;写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换;

注:此处认为二进制位的最低位为0位;

思路:你可能会联想到之前练习的”旋转字符串“类型的题目,可以先得到最右边的二进制位,然后再将剩余的二进制位依次向右移动,但是针对”比特位“进行操作显然是不方便的;

当所要交换的数据有偶数个的时候,便可以将偶数位上的所有的数据统一向左移动到奇数位上,对于奇数位上的数来说同理,将奇数位上的所有的数据统一向右移动到奇数位上;这样便可以达到奇偶项上的数的交换;

如何对比特位进行操作?显然是必须使用位操作符或者移位操作符,复习如下:

我们可以将奇数位上全是1的数与目标数值进行按位与,得到目标数值中奇数位上数据,再利用右移操作符>> 将奇数位上的数据向右移动一位;同理,可以将偶数位上全是1的数与目标数值进行按位与,得到目标数值中偶数位上的数据,然后再利用左移操作符<< 将偶数位上的数据向右移动一位;最后再将二者相加即可;

代码如下:

#define SWAP_BIT(n) (((n&0xaaaaaaaa)>>1)+((n&0x55555555)<<1))


int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d\n", SWAP_BIT(n));

	return 0;
}

总结

1、对于二进制位的操作,需要用到位操作符与移位操作符,对这些操作符要熟悉

2、求一个数值二进制位中1 的个数,计算 原数& (原数-1) 的次数 便可,这是一个很好的方法,因为无需遍历;

3、经过以上例题,可以感受到,常会用到右移操作符>>、按位与&、按位异或^  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值