数组中的数只出现一次

前言

中午在微薄上看道了九度的这道题,把题目先贴出来,分享一下我的解题思路吧

题目描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
输入:
每个测试案例包括两行:
第一行包含一个整数n,表示数组大小。2<=n <= 10^6。
第二行包含n个整数,表示数组元素,元素均为int。
输出:
对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。
样例输入:
8
2 4 3 6 3 2 5 5
样例输出:
4 6


排序方法

思路

最容易想的方法当然也是时间复杂度最高的算法,我开始分两步完成:
  1. 快速排序,将数按照从小到大的顺序排序
  2. for循环遍历排序好的数组,找出只出现一次的两个数

代码(c语言)

#include <stdio.h>
#include <stdlib.h>
#define max 1000001

int compare(const void *a, const void *b);

int main()
{
	int i, n, count, k;
	int a[max];
	
	while(scanf("%d", &n) != EOF && n >= 2)
	{
		for(i = 0; i < n; i ++)
		{
			scanf("%d", &a[i]);
		}

		qsort(a, n, sizeof(a[0]), compare);

		for(i = 0, count = 1; i < n; i ++)
		{
			if(a[i] != a[i + 1])
			{
				if(count == 1)
				{
					printf("%d ", a[i]);
					count ++;
				}
				else
				{
					printf("%d\n", a[i]);
					break;
				}
			}else
			{
				for(k = i + 2; k < n; k ++)
				{
					if(a[i] != a[k])
						break;
				}
				i = k - 1;
			}
		}
	}
	
	return 0;
}

int compare(const void *a, const void *b)
{
	const int *p = a;
	const int *q = b;

	return *p - *q;
}

运行结果



缺点:

最容易想到的往往时间复杂度最高,本题采用这种方法只能通过一个测试用例,其它均超时!!

异或位运算


思路

根据异或的运算性质,偶数个相同的数进行异或为0,奇数个相同的数异或为该数。所以对数组中所有的数进行一遍异或,最后的结果result = a ^ b. a和b为只出现一次的两个数。
假设a = 0010, b = 0110, 则result = 0100.首个二进制为1的是第三位。说明a和b首个不相同的位数出现在第三位,而第三位要不为0,要不为1,可以根据这个特性将数组分为两部分,分别异或,得出的两个结果即为a和b。

代码(c语言)

#include <stdio.h>
#include <stdlib.h>
#define max 1000001

int main()
{
	int i, n, result, p, q, t;
	int a[max];

	while(scanf("%d", &n) != EOF && n >= 2)
	{
		for(i = result = 0; i < n; i ++)
		{
			scanf("%d", &a[i]);
			result ^= a[i];
		}

		t = 1;
		while((result & t) == 0)
		{
			t <<= 1;
		}

		for(i = p = q = 0; i < n; i ++)
		{
			if(a[i] & t)
			{
				p = p ^ a[i];
			}else
			{
				q = q ^ a[i];
			}

		}

		p > q ? printf("%d %d\n", q, p) : printf("%d %d\n", p, q); 
	}

	return 0;
}

运行结果




点评

时间负责度为O(n),但是没有排序方法通用行强。

posted @ 2013-01-29 14:59  java程序员填空  阅读(240)  评论(0编辑  收藏  举报