算法学习(2):异或运算

异或运算

异或运算法则

异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1)。

异或运算的性质

1)0⊕N=N,N⊕N=0;
2) 异或运算满足交换律和结合律,即 a⊕b=b⊕a, (a⊕b)⊕c=a⊕(b⊕c);

异或运算的性质在交换两个数的swap函数中的应用

void swap(int a, int b)
{
  a = a ^ b; //此时a = a ^ b, b = b;
  b = a ^ b; //此时b = a ^ b ^ b = a ^ 0 = a, a = a ^ b;
  a = a ^ b; //此时a = a ^ b ^ a = a ^ a ^ b = 0 ^ b = b, b = a; 完成交换
}

采用异或运算完成的swap函数的优缺点

优点:不用再另外开辟空间,且异或运算属于位运算,速度快;
缺点:必须保证a与b所指向的空间是不同的(值可以相同),否则将会得到a = b = 0。

异或运算的一道编程题

给定一个数组arr:
(1)数组中只有一种数出现的次数是奇数次,其余数出现的次数都为偶数次。用时间复杂度为O(N)、额外空间复杂度为O(1)的算法求出出现次数为奇数次的数。
(2)数组中有两种数出现的次数是奇数次,其余数出现的次数都为偶数次。用时间复杂度为O(N)、额外空间复杂度为O(1)的算法求出出现次数为奇数次的数。

第(1)问解题思路:把数组中的所有数都一起做异或运算。

void printOddTimesNum1(vector<int> arr)
{
    int eor = 0;
    for (int cur : arr)
    {
        eor ^= cur;
    }
    cout << eor << endl;
}

第(2)问解题思路:假设题设中要求的结果数字分别为a和b,把数组中的所有数都一起做异或运算,得到a ^ b,根据题意a一定不等于b,所以a ^ b一定不为0,则a ^ b的二进制数中一定有一位数为1,是由a在此位上的0和b在此位上的1(或者是a的1和b的0)异或运算得到,利用这一位把数组中的所有数字分成两组,一组是在这一位上为0的数,另一组是在这一位上为1的数,a和b各自在一组,用其中一组的所有数字做异或运算,因为除了在这一组的a或者b之外,其他的数字都是偶数次,运算到最后会得到a或者b,再把求得的a或者b再次与a ^ b做异或运算就得到另一个数字。

void printOddTimesNum2(vector<int> arr)
{
    int eor = 0;
    for (int cur : arr)
    {
        eor ^= cur;
    }
    int rightOne = eor & (~eor + 1); //得到最低位的1
    int onlyOne = 0;
    for (int curNum : arr)
    {
        if ((curNum & rightOne) == 0)
        {
            onlyOne ^= curNum;
        }
    }
    cout << onlyOne << " " << (eor ^ onlyOne) << endl;
}
posted @ 2022-07-18 15:10  小肉包i  阅读(127)  评论(0)    收藏  举报