数组中的数只出现一次
前言
中午在微薄上看道了九度的这道题,把题目先贴出来,分享一下我的解题思路吧
题目描述: 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组大小。2<=n <= 10^6。 第二行包含n个整数,表示数组元素,元素均为int。 输出: 对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。 样例输入: 8 2 4 3 6 3 2 5 5 样例输出: 4 6
排序方法
思路
最容易想的方法当然也是时间复杂度最高的算法,我开始分两步完成:
- 快速排序,将数按照从小到大的顺序排序
- 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),但是没有排序方法通用行强。