找出数组中只出现一次的数(single number )

来源:互联网 发布:java utf8 utf16 编辑:程序博客网 时间:2024/05/16 17:52

给定一个数组,里面除了一个数字出现了一次外,其他所有数字都出现了三次,求找出这个出现一次的数字,请用O(n)时间复杂度和O(1)空间复杂度

分析:如果其他数字都出现两次,只要把所有数字都异或一下就能剔除出现两次的数字,但是这里出现三次,怎么样才能把出现三次的数字都剔除呢?可以把一个整数看成一个是由(sizeof(int)*8)的bit组成的数字,对于某个出现三次的数字来说,当它出现三次后,它的每个bit位相加的结果肯定能被3整除,同理,当把数组的所有数字相加后,出现过三次的数字肯定会把相应bit位上形成一个3的倍数,而那个出现一次的数就是每个bit位上除以3的余数组成的数。

实现方法可以参考下面两种:

方法1:创建一个长度为sizeof(int)*8 的数组count[sizeof(int)*8],count[i] 表示在在i 位出现的1 的次数。如果count[i] 是3 的整数倍,则忽略;否则就把该位取出来组成答案。 

方法2:用one 记录到当前处理的元素为止,二进制1 出现“1 次”(mod 3 之后的1)的有哪些二进制位;用two 记录到当前计算的变量为止,二进制1 出现“2 次”(mod 3 之后的2)的有哪些二进制位。当one 和two 中的某一位同时为1 时表示该二进制位上1 出现了3 次,此时需要清零。即用二进制模拟三进制运算。最终one 记录的是最终结果。

代码如下:

//方法一

int singleNumber(vector<int>& myarray){

    vector<int> count(sizeof(int)*8);

    for(int i = 0;i<myarray.size();i++){

       for(int j = 0;j<count.size();j++){

           count[j] += ((myarray[i]>>j)&1);

           count[j] %= 3;

       }

    }

    int res = 0;

    for(int i = 0;i<count.size();i++)

       res += (count[i]<<i);

    return res;

}

 

//方法二

int singleNumber2(vector<int>& myarray){

    int one = 0,two = 0,three = 0;

    for(int i = 0;i<myarray.size();i++){

       two |= (one&myarray[i]);

       one ^= myarray[i];

       three = two&one;

       one ^= three;

       two ^= three;

    }

    return one;

}


这两种方法的时间复杂度都为O(n),空间复杂度都为O(1),但是实现上来说,方法二用到的空间和计算代价都优于方法一。

本人水平有限,文章有错误的地方欢迎大家指出,有问题也希望大家能够留言交流,一起学习进步

0 0
原创粉丝点击