前提
Leetcode第136号题目——只出现一次的数字,之所以记录下这道题目,是因为它的解题方法使用到了——数字如何在计算机中存储的这个知识点。
正文
题目让找出非空数组中只出现一次的元素。这里先例举两个常规方法:
- 使用哈希表,哈希表中没有当前元素则添加,有当前元素则删除
- 对数组进行排序,然后遍历
当然这两个方法不是重点,重点是使用位运算的方法来解决该题。
在C++中,有关位运算的运算符有6个,分别是:
- a&b
- a^b
- a|b
- a&=b
- a^=b
- a|=b
分别是:与,异或,或,以及它们的复合赋值符号。
那么就有一个很有趣的事情是:一个数分别与本身做与,异或,或运算,结果是什么?
数字在计算机中是以二进制的方式存储的,比如说,a=5
,对应的二进制是0101
,所以5
在计算机中以0101
存储。可以推导:
5&5=5
5|5=5
5^5=0
0^5=5
发现了什么:一个数与本身与,或的结果还是其本身;一个数与本身异或的结果是0。
使用这个结论来解决136这道题目就非常简单了,只需要对数组中的所有元素做异或操作,结果就是只出现一次的元素,因为其它成对出现的元素经过异或后都为0了。
一些其它的技巧
判断一个数是奇数还是偶数
一般,给我们一个数判断是奇数还是偶数,最直觉的想法是:num%2
,对2取于。结果是0则为偶数,是1则为奇数。
这里给出一个使用位运算判断的方法:num&1
,将该数与1做位运算。结果是0则为偶数,是1则为奇数。为什么呢?
因为奇数的最低位一定是1,偶数的最低位一定是0。所以将该数与1做与运算后,只会取最低位的值,就可以判断是奇是偶。
总结
这道题目没有使用高深的算法,就是一个简单的位运算,但是它充分利用了计算机本身的特性。类似于这样的还有,当我们要给一个数除以2时,我们可以使用**>>**右移运算符替代,等等。