位运算

原博客:https://blog.csdn.net/deaidai/article/details/78167367?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

 

一些小技巧

1、技巧一:用x&x-1 消去x的二进制形式中的最后一位1

x=1100
x-1=1011
x&x-1=1000 (与x相比,第二个1,即最后一位1被消去) 

1.1应用一:用O(1)时间检测整数n是否是2的幂次

思路:如果n是2的整数次幂,则它的二进制只有一位1,用x&x-1来判断,若=0则是2的整数次幂,!=0则不是

string if2(int x){
	x=x&(x-1);
	if(x==0){
		return "Yes";
	}
	else{
		return "No";
	}
}

1.2应用二:计算一个32位二进制数的二进制表示中有多少个1

思路:x&x-1循环,每次都消去一个1 计数++,直到结果为0

int if2(int x){
	int num=0;
	while(x!=0){
		x=x&(x-1);
		num++;
	}
	return num;
}

1.3应用三:将整数a转化为整数b,需要改变多少个二进制位

思路:a与b异或,结果中1表示异,x=a^b,再用x&x-1来计算结果中的二进制位数

int howManyChange(int a,int b){
	int x=a^b,num=0;
	while(x!=0){
		x=x&(x-1);
		num++;
	}
	return num;
} 

2、技巧二:用二进制进行子集枚举

2.1应用一:给定一个含不同整数的集合,求他的所有子集

例:{2,5,7}的子集

思路:有三个数,用三位二进制数,第一位取1表示该子集里包含2,取0表示不包含,如下

000 ∅
001 {7}
010 {5}
011 {5,7}
100 {2}
101 {2,7}
110 {2,5}
111 {2,5,7}

#include
#include 
using namespace std;
int a[15];
 
int main() {
	int n;
	while(scanf("%d",&n)){    //输入数字的个数
		for(int i=0;i>1;
			}
			cout<

3、技巧三:a^b^b=a

3.1应用一:数组中,只有一个数出现一次,剩下都出现两次,找出出现一次的

例,给出数组[1,2,3,4,3,2,1],最后返回4

#include
#include 
using namespace std;
int a[15];
 
int main() {
	int n;
	while(scanf("%d",&n)){    //输入数字的个数
		int result=0;
		for(int i=0;i

3.2应用二:数组中,只有两个数出现一次,剩下都出现两次,找出出现一次的

思路:设两个只出现了一次的数为x,y,在第一题的基础上,先对数组中的所有数进行异或,得到结果res ,res=x^y。res的二进制表示中最后一位1的含义是x和y的该位不相同,一个为1,一个为0,可以用这一位来找到x和y其中之一,然后找到其中一个,另一个自然就找到了。

找x或y其中之一的方法详细思路:找到res二进制表示中的最后一位1,判断数组中的所有数,将该位为1的数放到数组b中,对数组b所有数进行异或,最后就可以求得x或y,再根据x^y=res,y=res^x,求得另一个数

1 2 2 3 4 4 5 3


#include
#include 
using namespace std;

void findTwo(int b[15],int n){
	int res=0;
	for(int i=0;i>=1; 
	} 
	int x=0;
	for(int i=0;i>location)&1!=0){    //a[i]>>location即为a[i]的location位,它与1相与=1说明a[i]的该位为一 
			x^=b[i];
		}	
	}
	int y=res^x;
	printf("x:%d y:%d\n",x,y);
}
int main(){
	int n;
	int a[15];
	while(scanf("%d",&n)){    //输入数字的个数
		for(int i=0;i

还剩一点应用不太懂,搞懂了再补上

 

 

 

 

 

你可能感兴趣的:(位运算)