这三道题目很考察bit操作思路。使用了下列几个技巧。
1.如何取得一个int数字二进制表示的每一位,方法就是使用逻辑右移操作,逐位与1做&操作;
2.亦或xor是一个很关键的操作,0与任意一个数做偶数次xor结果是0,奇数次结果是1。
3.位操作是满足交换律的,因为每一个bit是满足的。
4.如何得到一个int的最右侧的第一个1?方法是与其相反数做&。因为相反数是取反加一,取反以后,第一个1右侧的0变为1,加一以后这些1变为0,相应的第一个1变回为1,比这个1高的位全是0,因为取反。最终就得到了一个只包含最右侧1的掩码,其余是0。这个方法是O1的。
第一题:https://leetcode.com/problems/single-number/?tab=Description
第一道题就是用了2,3性质直接得到的。使用交换律把相同的连续排放,最后xor结果是0,再和只出现一次的xor,得到本身。代码不贴了,很简单。
第二题:https://leetcode.com/problems/single-number-ii/?tab=Description
第二题是说有些数字出现了3次,有一个只出现一次。
其实是之前题目的延伸,可以使用位运算得到所有这列题目的规律,leetcode里面有。不过这里我觉得另一个思路很好很直观,也可以给出通解,只不过是O(32n)的。思路就是逐位相加,和取模,比如其余出现了k次,就模k,那么余数就是单独的那个数字在该位的二进制。
第三题:https://leetcode.com/problems/single-number-iii/?tab=Description
是第一题的变种,一些出现两次,有两个数字a,b不同且各出现一次。先做一趟xor假设结果为x,那么x是a,b亦或的结果,因为二者不同那么x中必然有一位是1,我们使用方法4得到这个1,是一个只包含一位1的掩码。然后做第二趟xor,这次使用掩码分组操作。就可以区分a和b。其余额元素也会分组,不过不影响结果,因为肯定是在某一组中出现两次。