学习笔记2:c++位运算-异或运算

先看一道题:

Single Number

 

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

这是Leetcode上的一道题,意思是n维数组中除了一个元素出现一次之外,其他的全部出现两次,这道题明显符合异或的性质,两个相同的元素异或就会变成0,利用这一性质,这道题就变得特别简单了。

void main(){
	int t=0;
		for(int i=0;i<n;i++){
			t^=A[i];
		}
	printf("%d\n",t);
}


如果将题目改一下,若剩下的不是一个元素,而是剩下两个不同的元素,求其和呢?

如果还像上面那样求,最后出来的结果是这两个不同元素异或的值,不是最终结果,利用异或的结果也是求不出两个值的和的,所以要换种思路。


有一种思路是,定义一个比较大的数组,大于n位数组中每一个正整数,数组中存放该数值是否被访问过,被访问第二次就把该值变为0;

定义一个存放结果的变量result,初始值定义为0。

遍历数组,如果该元素被访问一次,则将该值加到result上,否则(包括访问0次或2次)从result中减掉该值。

具体实现如下:

int main() {
	freopen("C:\\in.txt","r",stdin);
	int n,g,result,i;
	bool vis[10005];
	while(~scanf("%d",&n)){
		result=0;
		for(i=0;i<=10000;i++)vis[i]=0;
		for(i=0;i<n;i++){
			scanf("%d",&g);
			if(!vis[g])result+=g;
			else result-=g;
			vis[g]^=1;
		}
		printf("%d\n",result);
	}
	return 0;
}

其中用到了vis[g]^=1,也就是将该值取反,异或速度会比比较然后再赋值快。

但是如果要是n值非常大或者是数组中可以有负值,这个方法就不行了

另一种思路还是二进制的思想,我们将所有的数进行异或,结果一定是那两个不同的数的异或值,因为两个数不同,所以异或值不为0,我们根据异或值中某一位1的位置,将数组分为两个数组,每个数组中都符合只有唯一的一个不同的数

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;

int main(){
	int a[10]={1,2,3,1,2,3,4,4,5,6};
	int arr1[5],arr2[5];
	int t=0;
	//先做异或
	for(int i=0;i<10;i++)
		t^=a[i];

	//找到t二进制中最后的1的位置
	int idx=1;
	while(!t&idx)idx<<=1;

	//根据idx位置是0或1将数组a分成arr1和arr2两个数组
	int j1=0,j2=0;
	for(int i=0;i<10;i++)
		if(a[i]&idx)arr1[j1++]=a[i];
		else arr2[j2++]=a[i];

	int t1=0,t2=0;
	for(int i=0;i<j1;i++)t1^=arr1[i];
	for(int i=0;i<j2;i++)t2^=arr2[i];

	cout<<t1<<" "<<t2<<endl;
    return 0;
}

然后还有一题,大意是数组n中除了一个元素只出现一次外,其他元素全部出现3次,求这个特殊的元素,这道题通过位运算可以在线性时间内求出结果,

具体参见我的另一篇文章:http://blog.csdn.net/starcuan/article/details/18219623

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值