聊聊位运算那些事(2)

引发学习位运算的原因是在网上浏览到了几道题:

第一题:

有一个给定的数组,其中仅有一个元素出现了一次,而其他的元素出现了两次。问如何找出这个仅出现一次的元素呢?

  解:

其实看到这一题的第一反应是利用数组下标法。但是它的空间复杂度是O(n),是时间复杂度是O(n).

但是我们可不可再优化以下,尽量降低它的复杂度?

紧接着,又想到了利用哈希表存储每个元素出现的次数,当一个元素出现两次时,就从表中删除,最后只有一个元素。此举可以降低空间复杂度,但是并不是最优的选择。

而推荐

的解法就是利用异或运算。

举例说明:

1,2,1,2,5

运用异或后,1^2^1^2^=1^1^2^2^5。so根据异或的性质,最后0^5为5。

int find(int arr[100]){
	int temp=arr[0];
	for(int i=0;i<100;i++){
		temp=temp^arr[i];
	}
	return temp;//直接返回了答案!
}

第二题 

判断一个数是不是2的幂次

解:

我们观察是二的幂次数的二进制形式可以发现,其只有一位为1,其余位均为0.

那么我们可以根据这个性质来进行分析。

我们可以用到x&(x-1)这一操作。当最后的结果是0时,说明只有一位是1,说明其是二的幂次。

我们下边进行举例说明:如该数是1000,则其减1后的结果为0111,进行与运算后的结果为0;如果这个数是10100,减一后的结果是10011,进行与运算后的结果是1。

第三题:

找出不大于n的最大的2的幂指数;

解:

按二进制的形式来看,如10100,结果应该是最左边的非0位,故为4。所以我们得找出一种操作,是得10100000变为11111111,然后加1,得到了100000000,然后100000000>>1=10000000。

接下来,重点是变为全1的操作。假设这个数是8位的,而我们一定可以知道第k位一定是1((从左至右数的第一个非0位)。我们接下来让其右移一位,并进行或运算,得到的结果为第k位,第k+1位,一定是1。紧接着我们再进行右移两位第,则或运算后,第k,k+1,k+2,k+3位均为一定为1。依次类推进行右移四位,则可以保证这八位一定全为1.

x|x>>1;
x|x>>2;
x|x>>4;

之后再进行减一后移位操作。

int find(int x){

x|x>>1;
x|x>>2;
x|x>>4;
return (x+1)>>1;
}
发布了50 篇原创文章 · 获赞 13 · 访问量 8828

猜你喜欢

转载自blog.csdn.net/weixin_43770577/article/details/90700967