你值得拥有的---位运算

1.一些常规的计算:

x ^ 0s = x    x & 0s = 0   x | 0s = x

x ^ 1s = ~x  x & 1s = x   x | 1s = 1s

x ^ x = 0      x & x = x     x | x = x

^  (异或)-----  相同的为0,相异的为1

2.位运算实用的技巧

(1)  x & (x-1)

可以消去x中(二进制状态下)的最后面的 1 .

(2) 求数组的子集

[ 1 , 2 , 3 ]

n(元素的个数)  N=2^n (二的n次方)

子集为从0到N-1对应下的二进制:

0     000   {}

1     001   {1}

2     010    {2}

3     011    {1,2}

4     100    {3}

5      101   {1,3}

6      110   {2,3}

7      111    {1,2,3}

#include<iostream>
using namespace std;
int main()
{
	int a[3] = { 5,6,7 };
	int n = pow(2, 3);
	for (int i = 0; i < n; i++)
	{
		if (i == 0) {
			cout << "空集";
			continue;
		}
		int x = i;
		int count = 0;
		cout << " ";
		while (x)
		{
			if (x & 1) {
				cout << a[count];
			}
			x >>= 1;
			count++;
		}
	}
	return 0;
}
空集 5 6 56 7 57 67 567
C:\Users\17281\source\repos\Project69\Debug\Project69.exe (进程 14144)已退出,代码为 0。
按任意键关闭此窗口. . .

(3) a^b^b=a

例1:数组中只有一个数出现过一次,其余数出现过两次,求这个出现一次的数

解:从头异或到底最后得到的数就答案

例2:数组中只有二个数出现过一次,其余数出现过两次,求这两个数。

问题
Given [1,2,2,3,4,4,5,3] return 1 and 5

解题思路
有了第一题的基本的思路,我们不妨假设出现一个的两个元素是x,y,那么最终所有的元素异或的结果就是res = x^y。并且res!=0,那么我们可以找出res二进制表示中的某一位是1,那么这一位1对于这两个数x,y只有一个数的该位置是1。对于原来的数组,我们可以根据这个位置是不是1就可以将数组分成两个部分。求出x,y其中一个,我们就能求出两个了。

#include<iostream>
using namespace std;
int main()
{
	int a[8] = { 1, 2, 2, 3, 4, 4, 5, 3 };
	int res = 0,ans,count=0,x=0,y=0;
	for (int i = 0; i < 8; i++)
	{
		res = res ^ a[i];
	}
	ans = res;
	//找到最右边的1所在的二进制位数
	while (1)
	{
		if (res & 1)
		{
			break;
		}
		count++;
		res >>= 1;
	}
	for (int i = 0; i < 8; i++)
	{
		if ((a[i] >> count) & 1)
			x = x ^ a[i];
	}
	y = ans ^ x;
	cout << x <<" "<< y;
}

例3:数组中只有一个数出现过一次,其余数出现过3次,求这个出现一次的数

问题

Given [1,1,2,3,3,3,2,2,4,1] return 4

解体思路

对于每一个二进制位,如果只出现一次的数在该二进制位为1,那么这个二进制位在全部数字中出现次数无法被3整除。

#include<iostream>
using namespace std;
int bit[32];//用于存储各位二进制下对应的1的总数;
int main()
{
	int res = 0;//记录答案
	int a[10] = { 1,1,2,3,3,3,2,2,4,1 };
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 32; j++)
		{
			bit[j] += ((a[i] >> j) & 1);
		}
	}
	for (int i = 0; i < 32; i++)
	{
		if (bit[i] % 3 == 1)
			res = res + 1 << i;
	}
	cout << res;

}

(4) 可以判断一个数的奇偶性:

判断该数二进制下最后一位是否为1即可

例:3 -> 011, 6->110

(5) 可以用于交换两个数 交换 X ,Y;

常规的算法在此不写

位运算三步:

X=X ^ Y

Y=X^Y

X=X^Y

(6) 或:可以把两个数中的1全部保存下来,可能这么说有点抽象,下面举个实例:

例如将 abce 用 10111表示(按位表示)

int q=0;

s="abce"

for ( int i=0,i<strlen(s);i++)

{

q=q | 1<<(s[i]-'a');

}  

cout<<q;

(7)

判断一个数 x 是否为 2 的整数幂

法一:x & (-x) == x; 其中 x & (-x) 等于x的二进制表示里最右边一个1

法二:看一下x在二进制状态下表示是否只有一个1   x&(x-1) 可以消去x二进制下最后面的一位1

如果进行一次操作 x&(x-1) == 0 的话该数就为2的整数幂。

判断一个数 x 是否为 4的整数幂

如果这个数也是 4 的次方,那二进制表示中 1 的位置必须为奇数位。我们可以把 n 和二进制 的 10101...101(即十进制下的 1431655765)做按位与,如果结果不为 0,那么说明这个数是 4 的 次方。

bool isPowerOfFour(int n) {
return n > 0 && !(n & (n - 1)) && (n & 1431655765);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值