136 single number这题是从一串都出现过2次的数字里找出只出现了1次的那个数字,137 single number II 是从一串都出现过3次的数字里找出只出现了1次的那个数字。
136
有4种做法。
brute force
对每个数字都向左右搜索,看有没有重复的,没有就输出。或者,用一个list,遇到第一个的时候add,遇到第二个时候remove。时间都是O(n2)。HashMap
记录每个数字出现的次数。不够最后还要遍历一遍。时间是O(n)。Math
用set保存数字,2∗(a+b+c)−(a+a+b+b+c)=c,最后singleSum *2 - sum就是结果。问题是如果数字是INTEGER的最大值,加起来或者乘法都会溢出。位运算
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
我觉得位运算的题目不太容易考,很晦涩,看得很绝望。