今天看到网上前辈的解题思路,再次想起了上次参加去哪儿网笔试的这种题了。整理一下做个笔记,自己也吸收吸收!
那次笔试题目要求大致是:
已知了一个数组,比如:[2,3,3,6,5,2,5,],这个数组中除了一个数外,其他的任何数都是出现了2次,让写出找出这个数组中出现一次的这个数的代码!
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
当时的解题思路是:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
对这个数组进行排序,然后从数组的首尾向中间遍历依次把前后两个数加起来,如果挨着的都是出现两次的数,必然会是每两次之和是相等的,等发现每两次之和出现不等了,那么这个只出现一次的数,就必然在这四个数之中。然后再对这四个数做判断,最后找出需要找到的那个出现一次的数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
今天看到了别人的解题思路,并且自己想明白后,觉得的自己那个办法弱爆了。现在做个笔记,以后也学聪明点!
利用异或位运算巧妙的解题思路:
n:为数组长度
A:为目标数组
res:就是那个只出现一次的数
int singleNumber(int A[], int n) {
int res = 0;
for(int i = 0; i < n; i++){
res ^= A[i];
}
return res;
}
分析:
1. 它利用了之前博客里面说的,任何一个数在与自己异或时,结果都为0 ,同时任何一个数与0异或处理时结果都为本身.
那么这里: res = 2 ^ 3^ 3^6^5^2^5 可以化简为: res = (2^2)^(5^5)^(3^3)^6 那么res = 6^0 = 6
这就是最后的答案,找到了只出现一次的数了!几行代码就搞定了,我之前想的那个太复杂了啊。效率和这个简直没法比!
思路拓展一下:
上面那种解题法,也适用于找出唯一一个出现奇数次数的数,因为偶数次出现异或都会把他消为0,最后依然可以得到想要的结果!
假如其他所有的数都出现3次,让在里面找出现一次的数怎么办呢?或者其他所有的数都 出现4次,出现5次,出现6次.......出现N次,要求在里面去寻找出现了1次,2次 3次,总之和其他不同次数的数值时,该如何下手呢??
解题思路:
可以想象,把所有的数以二进制位一一列下来,按位对齐来看。如果要找的数在该位上没有即在该位上是0,那么其他所有的数把这个位上的0 1 加起之和,对4 (出现的次数)取模 一定是等于0 的,即一定是能整除他们出现的次数的。所以,我们用这种思路,去判定我们要找到的那个数,在哪些位上是1 哪些位上是0 ,最后转为10进制就是我们需要的结果了!![肯定不能超过数组中最大的那个数的二进制位数]
下面这个是前辈另一种解题方法:正在学习中
int singleNumber(int A[], int n) {
int ones = 0;//记录只出现过1次的bits
int twos = 0;//记录只出现过2次的bits
int threes;
for(int i = 0; i < n; i++){
int t = A[i];
twos |= ones&t;//要在更新ones前面更新twos
ones ^= t;
threes = ones&twos;//ones和twos中都为1即出现了3次
ones &= ~threes;//抹去出现了3次的bits
twos &= ~threes;
}
return ones;
}