25 只出现一次的数字
https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/1/array/25/
用到异或去重的方法。异或(^)运算有如下性质:
- 交换率 a^b = b^a
- 结合律 a^b^c = a^(b^c)
- a^a=0; a^0=a; a^(-1)=~a;
去重利用的当然是a^a=0,a^0=a这2条性质了。题中的数组除了一个数只出现1次以外,其他数都出现2次,
不难理解只要把数组元素挨个异或,最后得到的结果就是那个落单的数字了。
int singleNumber(int* nums, int numsSize) {
int i=0;
int res=0;
for(;i<numsSize;i++){
res^=nums[i];
}
return res;
}
还可以参考下面这篇文章:
https://leetcode.com/submissions/detail/153326640/
如果有两个只出现1次的元素怎么办呢?思路是,把数组分成2部分,每部分含有1个落单的数字,
成对的数字也要分在同一个组里,不能一边一个。这样就又回到了原题的模式了。
问题是怎么划分这两个数组呢?
第一步,取整个数组的异或,得到的结果是两个落单元素的异或结果。
第二步,从这个结果中,找出右边开始第一个为1的bit位。这说明这一位两个数字一个是0一个是1,这一位就是两个落单元素的不同点,按照这个特征就可以把两个元素分开,同时还可以保证不会把成对的元素分到两个区里,因为成对的元素这个bit位上的值一定是相同的。
第三步,当然,第二步的分组并不需要实际操作,只需要遍历数组,按照特征分别进行异或去重即可。
在第二步中,用到的一个技巧是:
对于一个数字X,X&(-X)之后得到的数字,是把X中最右边的1保留下来,其他位全部为0。