一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 关键词:数组 次数 异或
看到这题就想起那个只出现一次的字符。不过这题已知条件更多一点,至少我们知道会有两个出现一次的数字,而且其他数字成双成对出现。
第一反应当然是排序啦(N·log(N)),然后利用栈,进去相同就弹出,最后剩下俩数字。 时间复杂度:O(N·log(N) + N) 空间复杂度:O(1)
Python class Solution: # 返回[a,b] 其中ab是出现一次的两个数字 def FindNumsAppearOnce(self, array): array.sort() ans = [] for a in array: if not ans or a!=ans[-1]: ans.append(a) elif a == ans[-1]: ans.pop() return ans C++ class Solution { public: void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) { vector<int> ans; sort(data.begin(), data.end()); for(int i=0; i<data.size(); i++){ if(ans.empty() || data[i] != ans.back()) ans.push_back(data[i]); else ans.pop_back(); } *num1 = ans[0]; *num2 = ans[1]; return; } };然后神奇的教科书还有一种解法,达到了理论上最小的复杂度(N),那就是利用异或的特性: 交换律:A ^ B = B ^ A 其他:A ^ A = 0, A ^ 0 = A
1)假设数组是[a, c, d, b, d, c],对所有数字异或,根据交换律a ^ c ^ d ^ b ^ d ^ c = a ^ b ^ (c ^ c ^ d ^ d) = a ^ b ^ 0 = a ^ b。
2)现在我们得到一个k = a ^ b,k中如果某位为0代表a和b该位相同,如果为1代表a和b该位不相同。我们找一个k中为1的任何一位作为标志(这里我们用第一个为1的位s),因为a、b在这一位不同,那么他们一个是0,一个是1。我们把s位是1的数字分为一组,剩下是0的作为另外一组。这两组中分别包含a、b以及其他的相同数字。假设第一组是[a, c, c, …],重复第一步方法,将这个数组全部异或,我们可以得到a ^ (c ^ c ^ …) = a,同理b ^ (d ^ d ^ …) = b
时间复杂度:O(N) 空间复杂度:O(1)
Python class Solution: # 返回[a,b] 其中ab是出现一次的两个数字 def FindNumsAppearOnce(self, array): c = 0 for n in array: c = c ^ n index = 1 while index & c == 0: index = index << 1 a, b = 0, 0 for n in array: if index & n == 0: a = a ^ n else: b = b ^ n return [a, b] C++ class Solution { public: void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) { int c = 0; for(int i = 0; i < data.size(); i++) c = c ^ data[i]; int index = 1; while((index & c) == 0) index = index << 1; int a= 0, b = 0; for(int i = 0; i < data.size(); i++){ if((index & data[i]) == 0) a = a ^ data[i]; else b = b ^ data[i]; } *num1 = a; *num2 = b; return; } };