CrackingtheCodeInterview之位操作

本文介绍了多种位操作技巧及其应用场景,包括位掩码使用、位翻转、位计数等,并提供了具体的代码示例,帮助读者掌握高效编程方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NO1. 给定两个32位的整数N与M,以及表示比特位置的i与j。编写一个方法,将M插入N,使得M从N的第j位开始,到第i位结束。假定从j位到i位足以容纳M,也即若M=10011,那么j和i之间至少可容纳5个位。例如,不可能出现j=3和i=2的情况,因为第3位和第2位之间放不下M。

示例:输入:N=1000 0000 0000 0000, M=1 0011,i=2,j=6

   输出:N=1000 0000 0100 1100.

解法:1、清除N的j到i位,可使用掩码11111000111与N相与即可。

2、将M左移i-1位

3、将M和N进行或操作即可。

int updateBits(int n,int m,int j,int i){
		int temp=((~0)<<j)|((1<<i)-1);//表示111110000011111
		n&=temp;//清空j到i之间的所有数,置为零
		m<<=(i-1); 
		return m|n;
	}

NO2. 给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表示。如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”。

解法:对于十进制整数化为二进制采用除2取余的方法,对于十进制整数则采用乘2取整的方法。

void printBinary(double num){
		if(num>=1||num<=0)
		return "ERROR";
		string str("0.");
		while(num){
			if(str.size()>=32)
			return "ERROR";
			num<<=1;
			if(num>=1){
				num-=1;
				str+='1';
			}
			else{
				str+='0';
			}
		}
		cout<<str<<endl;
	}

NO3. 给定一个正整数,找出与其二进制表示中1的个数相同、且大小最接近的那两个数(一个略小,一个略大)。

解法1:蛮力法,找出目标数字中1的个数,分别从该数字开始向两端扩散,直到某个数字跟目标数字中1的个数一样。

解法2:位操作法,首先找较大的数,记数字的尾部0的个数为c0,记数字最右端连着的1的个数为c1,令p=c0+c1+1,则p位为0,将p位改为1,在1--p-1位先清零,然后在最右端添加c1-1个1即可。然后找较小的数,记数字尾部1的个数为c1,记数字最右端连着的0的个数为c0,令p=c0+c1+1,则p位为1,将p为置为0,在1--p-1位先清0,然后在最左端添加c1+1个1即可。

解法3:算术解法,在位操作的基础上,根据c0和c1关系用数学表达式直接返回,代码更加简洁。

NO4. 解释代码((n&(n-1))==0)的具体含义。

a&b==0说明,a和b的取反,所有的二进制位都不相同,那么n和n-1具有取反关系,则表明n为2的指数幂。

NO5. 编写一个函数,确定需要改变几个位,才能将整数A转成整数B。示例,输入:31,14。输出:2

解法:A异或B得到了A和B中所有二进制位的关系,若相同就为0,若不同就为1,所以只需统计A^B中1的个数,在统计1的个数时,可以采用移位和1相与的操作完成,还可以采用一个更好的方法N&(N-1),检查最低有效位。

NO6. 编写程序,交换某个整数的奇数位和偶数位,使用指令越少越好(也就是说,位0与位1交换,位2与3交换,依次类推)。

解法:取0xAAAA为掩码和整数与操作,得到奇数位数字,向右移位1次,取0x5555为掩码和整数与操作,得到偶数位数字,向左移位1次,二者相或得到结果。

NO7. 数组A包含0到n的所有整数,但其中缺了一个。在这个问题中,只用一次操作无法取得数组A里某个整数的完整内容。此外,数组A的元素皆以二进制表示,唯一可用的访问操作是“从A【i】取出第j位数据”,该操作的时间复杂度为常数。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?

解法:若是可以直接访问所有整数,那我们可以计算所有整数的和,然后用公式n*(n+1)/2减去它就得到了缺少的数,此题也可通过计算每一个数的十进制然后利用以上方法,不过时间复杂度较高O(N*logN)。这里只能根据每一位中0和1的总个数的比较判断缺少数值在该位为0还是1了,若n为奇数,则总共有偶数个数,每一位的0和1应该相等,若n为偶数,则总数为奇数,每一位的0的个数和1中多一个。

NO8. 有个单色屏幕存储一个一维字节数组中,使得8个连续像素可以存放在一个字节里。屏幕宽度为w,且w可被8整除(即一个字节不会分布在两行上),屏幕高度可由数组长度及屏幕宽度推算得出。请实现一个函数drawHorizontalLine(byte[] screen,int width,int x1,int x2,int y),绘制从点(x1,y)到点(x2,y)的水平线。

解法:粗糙解法,for循环迭代逐个点打印,巧妙解法,逐个字节操作,两端分别操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值