在求解这道题之前,我们先来看一道比这道题简单点的题。
求一组数中只出现1次的那1个数,其他数字都出现了2次
方法1:
利用双层循环(都从0开始,保证count计数不出现问题),用计数器count,如果2个数相同,count++,若count == 1,则break
方法2:
利用异或运算符 (相同为0,相异为1)
异或运算是作用于补码上的运算符。
异或运算的几个特点:
- 0 ^ a = a
- a ^ a = 0
- a ^ b ^ a = b
- a ^ b = b ^ a
- a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
0 ^ a = a
a ^ b ^ a = b
扫描二维码关注公众号,回复: 12666311 查看本文章![]()
在这道题里面,我们就用到了a ^ b ^ a = b这一特点,由于这一组数中只有1个数字只出现了1次,其他数字都出现了2次,所以只要将这组数全部都异或在一起,异或的结果就是只出现1次的那个数字
int main() { int arr[] = { 1,1,2,2,3,3,4,5,5 }; int i = 0; int ret = 0; for (i = 0;i < sizeof(arr) / sizeof(arr[0]);i++) ret = ret ^ arr[i]; printf("%d ", ret); return 0; }
求一组数中只出现1次的2个数,其他数字都出现了2次
算法思路:
求只出现1次的2个数没法直接异或在一起去求了,因此我们需要想办法将这两个数分开,然后再进行分别求解。所以我们需要对这组数进行一个分组的操作,只要将这两个数分到不同的组中,每组的所有数再进行异或,最终2个组的结果就是这两个数。
我们根据什么标准进行分组呢?
我们可以先让这一组数全部异或在一起,然后异或的结果中找到二进制位为1的位,这位代表我们要找到的2个数字在这一位是不相同的,也就是可以拿这位当做分组的标准。
int main() { int arr[] = { 2,2,3,3,4,5,8,8 };//4,5 int i = 0; int res = 0; for (i = 0;i < sizeof(arr) / sizeof(arr[0]);i++) res = res ^ arr[i];//先把所有数字异或在一起 int num = 0; while (res & (1 << num) == 0) { num++;//确定第几位先出现了1(二进制中) } int retA = 0; int retB = 0; for (i = 0;i < sizeof(arr) / sizeof(arr[0]);i++) { if (arr[i] & (1<<num))//分组条件 { retA ^= arr[i];//组别1 } else { retB ^= arr[i];//组别2 } } printf("%d %d", retA, retB); return 0; }