问题
有一个 n 个元素的数组,除了两个数只出现一次外,其余元素都出现两次,让你找出这两个只出现一次的数分别是几,要求时间复杂度为 O(n) 且空间复杂度为O(1)(与 n 无关)。
例如:
输入: [1,2,2,1,3,4]
输出: [3,4]
解决方法
已知相同的两个数异或结果为0,在这里把所有元素都异或,那么得到的结果就是那两个只出现一次的元素异或的结果。
然后,因为这两个只出现一次的元素一定是不相同的,所以这两个元素的二进制形式肯定至少有某一位是不同的,即一个为 0 ,另一个为 1 ,现在需要找到这一位。
根据异或的性质 任何一个数字异或它自己都等于 0
,所以前面得到这个数字二进制形式中任意一个为 1 的位都是我们要找的那一位。
再然后,以这一位是 1 还是 0 为标准,将数组的 n 个元素分成两部分。
- 将这一位为 0 的所有元素做异或,得出的数就是只出现一次的数中的一个
- 将这一位为 1 的所有元素做异或,得出的数就是只出现一次的数中的另一个。
这样就解出题目。忽略寻找不同位的过程,总共遍历数组三次,时间复杂度为O(n)
代码:
1 #include<cstdio> 2 using namespace std; 3 4 const int maxn = 100000 + 10; 5 int num[maxn]; 6 int n; 7 8 int main() 9 { 10 scanf("%d", &n); 11 int res = 0; //记录所有数的异或结果 12 for (int i = 0; i < n; i++) 13 { 14 scanf("%d", &num[i]); 15 res ^= num[i]; 16 } 17 int pos; //记录“1”的位置 18 for(int i = 0;(1 << i) <= res;i++) 19 if (res & (1 << i)) { pos = i; break; } 20 int ans1 = 0, ans2 = 0; //记录两个结果 21 for (int i = 0; i < n; i++) 22 { 23 if (num[i] & (1 << pos)) ans1 ^= num[i]; 24 else ans2 ^= num[i]; 25 } 26 printf("%d %d\n", ans1, ans2); 27 return 0; 28 }
参考链接:
1、https://www.zhihu.com/question/269288074/answer/574871689
2、https://www.cnblogs.com/hezhiyao/p/7539024.html
原文地址:https://www.cnblogs.com/lfri/p/10424378.html
时间: 2024-10-10 13:41:30