异或运算的算法实操+找出一个数组中出现奇数次的数

1.什么是异或运算

异或,是一个数学运算符

如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

同时异或运算满足结合律,交换律,例如:a⊕(b⊕c)=(a⊕b)⊕c

异或也叫半加运算,其运算法则相当于不带进位的二进制加法:

二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0

2.异或运算来交换数值

有了以上基础,我们就可以使用异或运算来交换数值

1.普通交换

可能大家平时交换数值都是用一个新建temp来保存某个数的值

void swap(int i, int j) {
	int temp;
	temp=i;
	i = j;
	j = temp;
}

2.异或交换

接下来的交换是用异或运算来实现的,并不需要新建一个temp,这使得空间没有造成浪费,算法更加优化

void swap(int i, int j) {
	i = i ^ j;
	j = i ^ j;
	i = i ^ j;
}

让我们来看看

  1. i=i^j,第一步先不管
  2. j=i^j ,我们将第一步的式子代进去,利用异或运算的性质,j跟j异或等0,然后i跟0异或就等于i,所以j=i。
  3. i=i^j,我们将第二部j的式子代进去,原理跟第二步相同。

3.经典面试题: 数组里有一种数只出现奇数次,其他都是偶数次,请找出出现奇数次的数

void ARRAY(int arr[]) {
	int eor = 0;
	for (int i = 0; i < arr.length-1; i++) 
		eor ^= arr[i];
}

题目说了,只有一个数是出现奇数次,那其他出现偶数次的数都会在异或运算的时候等于0,0跟任何数异或运算后就等于任何数

4. 经典面试题:数组里有两种数出现奇数次,其他都是偶数次,请找出出现奇数次的数

void ARRAY(int arr[]) {
	int eor = 0;
	for (int i = 0; i < arr.length; i++) {
		eor ^= arr[i];  //现在eor是两个出现奇数次的数的异或,假如两个数为6和7
	}
	int rightOne = eor & (~eor + 1);  //提取出eor最右边的1
	int onlyone = 0;
	for (int i = 0; i < arr.length; i++) {
		if ((arr[i]&rightOne)==1)  //将6跟7分成两个部分,onlyone跟某个部分异或就会得到6或者7
			onlyone ^= arr[i];
	}
	cout << onlyone << "\t" << (eor ^ onlyone);//onlyone是一个出现奇数次的数,eor ^ onlyone是另一个出现奇数次的数

1. int rightOne = eor & (~eor + 1); //提取出eor最右边的1

可能大家不理解这一步是干什么的

eor是两个出现奇数次的数的异或,假如两个数为6和7

因为1的话肯定是1跟0异或,6的二进制是00000110,7是00000111

依次为标准,将6跟7分开

(arr[i]&rightOne)==1 可以将数组分为两个部分

一个部分有6,一个部分有7,然后其中的出现偶数次的数不变

分为两个部分后,就一直跟一个部分的数异或,就可以得到6或7,

最终在利用(eor ^ onlyone)可以得到另一个数


如果我表述的不够清楚,欢迎大家留言
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值