求一组数中只出现1次的2个数

在求解这道题之前,我们先来看一道比这道题简单点的题。

求一组数中只出现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

在这道题里面,我们就用到了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;
}

猜你喜欢

转载自blog.csdn.net/weixin_51696091/article/details/114176539