Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
int singleNumber(int A[], int n) { for(int i = 0; i < n; i++) { if(count(A, A + n, A[i])<2) return i; } }
然后搜肠刮肚想想那个算法可以优化为时间O(n)的复杂度的?分治?减治?贪心?动态规划???想多了。
1. 要求复杂度为O(n),白话点说也就是不能在一个n次循环里面添加任何循环,前面之所以失败就是因为这个原因。但是可以在循环外添加循环!!!
2. 既然可以在查找循环外添加循环,那么添加什么循环好呢?排序吧,没错!排序的数列干什么都方便!(感觉这个结论也适用很多地方)
排序之后就可以很方便地计算一个数在数列中出现了多少次了。一连出现多少次就是总共出现多少次了,方便吧。O(∩_∩)O~
1. 如果数列外空呢?
2 如果第一个是single number呢?
3 如果最后一个是single number呢?
//通用性好,适合两种情况 int singleNumber(int A[], int n) { //特殊情况1,2 if(n<=0) return -1; if(n==1) return A[0]; sort(A, A + n); int j = 1; for(int i = 0; i < n - 1; i++) { if(A[i] == A[i+1]) j++; else { if(j<2) return A[i];//这里修改为j<3那么就可以适用于single number II了。 j = 1; } } //特殊情况3 最后一个是single number的特殊情况 return A[n-1]; }
//2014-2-18 update int singleNumber(int A[], int n) { unordered_map<int, bool> ump_ii; for (int i = 0; i < n; i++) { if (!ump_ii.count(A[i])) ump_ii[A[i]] = true; else ump_ii.erase(A[i]); } return ump_ii.begin()->first; }
下面是Single number I 的位运算解法,思路就是每位bit出现2次就清零,所以可以不断异或运算得出最终结果:
//2014-2-18_2 update int singleNumber(int A[], int n) { int ans = 0; for (int i = 0; i < n; i++) ans ^= A[i]; return ans; }
Single number II 的位运算两种解法-- 参考leetcode论坛的代码:
方法一,int的32个bit逐个处理-这个方法还算简单的了:
int singleNumberII_36(int A[], int n) { int ans = 0; for (int i = 0; i < 32; i++) { int c = 0, d = 1<<i; for (int j = 0; j < n; j++) if (A[j] & d) c++; if (c%3) ans |= d; } return ans; }
方法二,进位,掩码清零法-本方法还是挺难理解的,要很小心,否则,很容易出错的,对位运算不熟悉是很难写出来的。
int singleNumber(int A[], int n) { int one = 0, two = 0; for (int i = 0; i < n; i++) { two |= A[i] & one;//two 积累值 one ^= A[i];//one不断求反 int t = one & two;//第三次的时候one和two都保留了该位的值 one &= ~t;//清零出现三次的该位的值 two &= ~t; } return one; }
不过上面的位运算方法一还是算好理解的了,而且也比较容易就可以用在其他情况,比如所有numbers都出现5次其中一个除外,面试的时候我觉得应该是首推算法吧。