巧用位操作符之——^异或运算符

来源:互联网 发布:部落冲突部落城堡数据 编辑:程序博客网 时间:2024/05/16 06:06
  1. 一道题目

题目:Single Number II Given an array of integers, every element appears three times except for one. Find that single one.
除了一个元素外,其它元素都是出现三次,求那个元素?

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

思路
题目对时间和空间复杂度进行了限制,利用位运算可以巧妙地解题。

异或位运算,相同则值为1,不同则值为0。所以数字和本身异或的结果为0。

更简单的题目:如果是除了一个元素,其它的都出现两次,那么数组汇总所有元素异或的结果就是所要找的元素。出现两次就是xor下。

对于出现3次的情况,还是用二进制位的方式来思考。

那么这些位,除去出现过一次的那个后,其他的都是3的倍数!- -我们把所有位1的个数mod 3,那么剩下的就是只出现过一次那个啦。

我们也没必要开个啥 int bit[32]的数组去统计的

模拟二进制加法,用两位来计数,到3就把该位清零。

bit2 bit1

bit1 如果该位来的是1 ,保持0,1,0,1。。。(也就是xor),如果是0就不变

当bit1=1的时候再来一个1,那么bit2=1

当这两个bit同时为1,说明这是3啦(二进制你想想嘛),该位清零。

class Solution {public:    int singleNumber(int A[], int n) {        //总的来说,就是统计各个二进制位1出现的次数。        //可以用one,two的每个二进制位分别代表对应位1出现的次数对三取模为1、2。        //另外one,two的某个二进制位都为0时,则表示那位1出现的次数取模正好为0。        int one = 0, two = 0; //刚开始在每位上1都没出现,所以都是0。        int three = 0; //当one,two的某个二进制位都为1时,表明已经出现了三次,可以取模。        for (int i = 0; i < n; ++i)        {            two |= one&A[i];            one ^= A[i];            three = one&two;            //当出现三次后,one,two清0,相当于取模            one &= ~three;            two &= ~three;        }        return one|two; //因为不知道那个数是出现一次还是两次,所以将出现一次或两次的都返回    }};

更简洁的写法

public int singleNumber(int[] A) {    int ones = 0, twos = 0;    for(int i = 0; i < A.length; i++){        ones = (ones ^ A[i]) & ~twos;        twos = (twos ^ A[i]) & ~ones;    }    return ones;}
  1. 交换两个数值
void Swap(int &a, int &b){    if (a != b)    {        a ^= b;   //a = a^b;        b ^= a;   //b = b^a ==> b = b^(a^b) = b^(b^a) = b^b^a = 0^a = a;        a ^= b;   //a = a^b = a^a==> a = (a^b)^a = a^b^a = a^a^b = b;    }}
0 0
原创粉丝点击