异或运算

异或运算:相同为0,不同为1,可以理解为无进位相加,且结果与参与运算的数顺序无关。在C++程序中,异或运算的符号为^。
两个重要的性质:
  a^a = 0;
  a^0 = a;
以下为一些应用到异或运算的题目:

1.如何不使用额外变量交换两个数的值?
  常规交换代码如下:(通过申请一个临时变量来保存其中一个值)

void Swap01(int& val1,int& val2)
{
	int temp = val1;
	val1 = val2;
	val2 = temp;
}

因为要求不使用额外变量,因此可以选择异或运算来实现:

void Swap02(int& val1,int& val2)
{
	val1 = val1 ^ val2;      // val^val2
	val2 = val1 ^ val2;      // val1^val2^val2 = val1
	val1 = val1 ^ val2;      // val1^val2^val1 = val2
}

实现细节:由于形参无法改变实参的值,传参时必须使用引用&。
2. 一个数组中,只有一种数出现了奇数次,其余数均出现了偶数次,如何找到出现奇数次的数?
  由于只有一种数出现了奇数次,因此对数组中所有数执行异或运算,由于a^a=0,因此异或结果即为出现奇数次的数。

int FindNum(vector<int>& v)
{
	int ans = 0;
	for (int i = 0; i < v.size(); i++)
	{
		ans ^= v[i];
	}
	return ans;
}

假设数组 v={1,2,3,4,4,3,2,4,1},实现结果如下:
在这里插入图片描述
3. 一个数组中,有两种数(假设是a和b)出现了奇数次,其余均出现了偶数次,如何找到出现奇数次的两种数?
  关键是区分出现奇数次的两种数,代码如下:

void FindOdd2(vector<int>& v)
{
	int ans = 0;
	for (int i = 0; i < v.size(); i++)
	{
		ans ^= v[i];
	}
	// 寻找能区分两数的方法---最右侧不为1的位
	int rightOne = ans & ((~ans) + 1); // 按位操作
	int ans1 = 0;
	for (int i = 0; i < v.size(); i++)
	{
		if ((v[i] & rightOne) != 0)  // 对应位为1
		{
			ans1 ^= v[i];
		}
	}
	cout << "其中一个出现奇数次的数为:" << ans1 << endl;
	int ans2 = ans1 ^ ans;
	cout << "另一个出现奇数次的数为:" << ans2 << endl;
}

对于数组中所有数的异或结果ans,假设其二进制中某一位(假设第i位)为1,即说明a和b的第i位不相同,因此可以利用该位来区分a和b。代码中采用的是求最右侧的1,即:
在这里插入图片描述
假设数组 v = {1,2,3,4,4,3,2,4,1,5},运行结果如下所示:
在这里插入图片描述

4.判断一个数中二进制个数(leetcode剑指offer15.二进制中1的个数

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n!=0)
        {
            // 寻找n中的最右侧的1
            int rightOne = n&((~n)+1);
            // 计数
            count++;
            // 抹去最右侧的1
            n ^= rightOne;
        }
        return count;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值