136. Single Number /137. Single Number II

136 single number这题是从一串都出现过2次的数字里找出只出现了1次的那个数字,137 single number II 是从一串都出现过3次的数字里找出只出现了1次的那个数字。

136

有4种做法。

  1. brute force
    对每个数字都向左右搜索,看有没有重复的,没有就输出。或者,用一个list,遇到第一个的时候add,遇到第二个时候remove。时间都是O(n2)。

  2. HashMap
    记录每个数字出现的次数。不够最后还要遍历一遍。时间是O(n)。

  3. Math
    用set保存数字,2∗(a+b+c)−(a+a+b+b+c)=c,最后singleSum *2 - sum就是结果。问题是如果数字是INTEGER的最大值,加起来或者乘法都会溢出。

  4. 位运算
    a⊕b⊕a=(a⊕a)⊕b=0⊕b=b

137

上述1,2,3都适用,3仍有溢出问题,4不适用了。

我有种方法,先排序,然后用一个count=3 来遍历,如果后一项等于前一项,那count--,否则判断count 如果不等于1,return 前一位,等于一就把count置3然后跳过本次循环。时间是O(nlogn)。

这题太难了,bit manipulation真是太难了:
这个O(32n)的方法稍微好理解点:
https://discuss.leetcode.com/topic/43166/java-o-n-easy-to-understand-solution-easily-extended-to-any-times-of-occurance
考虑:

...000111000...
...001001000...
...000111000...
...000111000...

public int singleNumber(int[] nums) {
    int ans = 0;
    for(int i = 0; i < 32; i++) {
        int sum = 0;
        for(int j = 0; j < nums.length; j++) {
            if(((nums[j] >> i) & 1) == 1) {
                sum++; //把每一个数字同一位的1加起来,0不用动
                sum %= 3; //到3就set到0
            }
        }
        if(sum != 0) {
            ans |= sum << i;//把sum(其实就是1,如果出现两次的话,也可以为2)复原到原来的位置
        }
    }
    return ans;
}

参考:http://www.jianshu.com/p/951100bb18c7

我觉得位运算的题目不太容易考,很晦涩,看得很绝望。

你可能感兴趣的:(136. Single Number /137. Single Number II)