位运算

匿名 (未验证) 提交于 2019-12-02 23:32:01

1.判断奇偶数

判断一个数是基于还是偶数,相信很多人都做过,一般的做法的代码如下:

if( n % 2) == 01     // n 是个奇数 } 

如果把 n 以二进制的形式展示的话,其实我们只需要判断最后一个二进制位是 1 还是 0 就行了,如果是 1 的话,代表是奇数,如果是 0 则代表是偶数,所以采用位运算的方式的话,代码如下:

if(n & 1 == 1){     // n 是个奇数。 } 

2.交换两个数(这个我在上篇写了,这里我就不写了)

博客链接:https://blog.csdn.net/weixin_43973189/article/details/90247492

3.找出没有重复的数

题目:给一组整型数据,这些数据中,其中有一个数只出现了一次,其他的数都出现了两次,找出这个数 。

一种方法是用哈希表,这种方法的时间复杂度为 O(n),空间复杂度也为 O(n)。

这里我们采用位运算来做:
两个相同的数异或的结果是 0,一个数和 0 异或的结果是它本身,所以我们把这一组整型全部异或一下,例如这组数据是:1, 2, 3, 4, 5, 1, 2, 3, 4。其中 5 只出现了一次,其他都出现了两次,把他们全部异或一下,结果如下:

1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 1 ^ 2 ^ 3 ^ 4 = (1 ^ 1) ^ (2 ^ 2) ^ (3 ^ 3) ^ (4 ^ 4) ^ 5 = 0 ^ 0 ^ 0 ^ 0 ^ 5 = 5。

也就是说,那些出现了两次的数异或之后会变成0,那个出现一次的数,和 0 异或之后就等于它本身。

这个方法的时间复杂度为 O(n),空间复杂度为 O(1)。

4.求2的n次方
用位运算来做。例如n = 13,则n的二进制表示为1101,那么2的13次方可以拆解为:

2 ^ 1101 = (2 ^ 0001) * (2 ^ 0100) * (2 ^ 1000)。

我们可以通过 & 1和 >>1 来逐位读取 1101,为1时将该位代表的乘数累乘到最终结果。代码如下:

int pow(int n) { 	int sum = 1; 	int temp = 2;//如果求其它数的n次方,改temp的值就行了 	while (n != 0) 	{ 		if (n & 1 == 1) 		{ 			sum *= temp; 		} 		temp *= temp; 		n = n >> 1; 	} 	return sum; } 

时间复杂度近为 O(logn)。这是比较复杂的方法。
也可以用

	cout << (1 << n) << endl; 

或者

	cout << (2 << (n-1)) << endl; 

5.找出不大于N的最大的2的幂指数

例如 N = 19,那么转换成二进制就是 00010011(这里为了方便,我采用8位的二进制来表示)。那么我们要找的数就是,把二进制中最左边的 1 保留,后面的 1 全部变为 0。即我们的目标数是 00010000。那么如何获得这个数呢?相应解法如下:

(1)找到最左边的 1,然后把它右边的所有 0 变成 1

                              0 0 0 1 0 0 1 1                                                                    0 0 0 1 1 1 1 1 

(2)把得到的数值加 1,可以得到 00100000即 00011111 + 1 = 00100000。

(3)把得到的 00100000 向右移动一位,即可得到 00010000,即 00100000 >> 1 = 00010000。

通过把 n 右移并且做或运算可实现第一步,代码如下:

n |= n >> 1; n |= n >> 2; n |= n >> 4; 

解释:
我们假设最左边的 1 处于二进制位中的第 k 位(从左往右数),那么把 n 右移一位之后,那么得到的结果中第 k+1 位也必定为 1,然后把 n 与右移后的结果做或运算,那么得到的结果中第 k 和 第 k + 1 位必定是 1;同样的道理,再次把 n 右移两位,那么得到的结果中第 k+2和第 k+3 位必定是 1,然后再次做或运算,那么就能得到第 k, k+1, k+2, k+3 都是 1,如此往复下去….

最终的代码如下:

int findN(int n){     n |= n >> 1;     n |= n >> 2;     n |= n >> 4;     n |= n >> 8 // 整型一般是 32 位,上面我是假设 8 位。     return (n + 1) >> 1;     //至于为什么是1248而不是12345678     //因为移动1位之后做或运算,那么k和k+1位变成1,移动2位那么k+1,k+2,k+3,k+4变成1。接着就有连续的四个1了,我们当然要移动4位,这样k+5,k+6,k+7,k+8也会是1了,已经把移动3位的给包含了 } 

这种做法的时间复杂度近似 O(1)。

以上内容转载自链接:https://mp.weixin.qq.com/s/C6o6T9ju34vAxNBg5zobWw

转载请标明出处:位运算
文章来源: https://blog.csdn.net/weixin_43973189/article/details/90261159
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!