打印出出现奇数次的整数 要求时间复杂度O(n),额外空间复杂度O(1)

题目:
给定一个整数数组arr,其中只有两个数出现了奇数次,其他的数都出现了偶数次,找出这两个数
例如:
arr=[1,5,1,5,2,6,4,6];
结果2,4
要求:
时间复杂度O(n),额外空间复杂度O(1)
解:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	printf("input arr size: ");
	int arr_size;
	scanf("%d", &arr_size);
	int *arr = (int *)malloc(sizeof(int)*arr_size);
	for (int i = 0; i < arr_size; i++)
		scanf("%d", &arr[i]);

	//求出这两个数异或的结果。
	int rtwo = 0;
	for (int i = 0; i < arr_size; i++)
		rtwo ^= arr[i];
//	printf("%d\n", rtwo);

	//求这个结果中为1的位,这个位两个数必定一个为1,一个为0,因为只有这样,这一位的结果才为1。
	int tbit = 1;
	while (1)
	{
		if (tbit & rtwo)
			break;
		tbit<<=tbit;
	}

	//把数组分为tbit位为0的和tbit为1的两组。必然一个结果在一组,另一个结果在另一组。
	//每组里除了相同的数也都被分到了一组。所以每组里除了结果其余的数仍出现偶数次
	int r1 = 0, r2 = 0;
	for (int i = 0; i < arr_size; i++)
		if (tbit&arr[i])
			r1 ^= arr[i];
		else
			r2 ^= arr[i];
	printf("%d %d\n", r1, r2);
}

原理:
k与0异或结果为k,k与k异或结果为0.
假如数组中只有一个数出现奇数次,其余的数都出现偶数次,数组从头到尾异或后,出现偶数次的数都被"消去了",异或的结果就是这个出现奇数次的数。
如果有两个数出现了奇数次,数组从头到尾异或后的结果就是这两个数异或的结果。
怎么"分开"这两个数呢?找到异或结果为1的一位(异或结果为1,说明这两个数这一位必定一个为1一个为0),用这一位把数组分成两组,每组分别异或,就能分别得到两个数了。

需要两次循环n趟,时间复杂度O(2n)=O(n)
需要一个整型变量保存两个数异或的结果。一个整型变量保存两数位不相同的位。额外空间复杂度为O(1)

发布了111 篇原创文章 · 获赞 13 · 访问量 3111

猜你喜欢

转载自blog.csdn.net/wx_assa/article/details/103691296