1、问题描述
一个数组中只有两个数字出现一次,其他所有数字都出现了两次,试着找出这两个数字。
2、算法分析
首先,数组中的元素个数必须为偶数(ps:如果数组元素为奇数,不满足条件 “只有两个数字出现一次,其他数字出现两次”)。其次,由于只有两个数字出现一次,那么这两个数字必然是不同的,从而得出这两个数字按位异或后的结果不为0。实际上按位异或整个数组的结果就是这两个不同的数字按位异或的结果,因为其他数字两两异或后都抵消掉了(ps:即就是0)。既然这两个数字不同,那么这两个数字的某一位必然不同,因此可以试着找出不同的位。以两个不同数字按位异或的结果中最右边出现1为条件,可以筛选出两组数据,从而将这两个不同的数字分开,最后分别按位异或每个数组的元素即可得到这两个不同的数字。
3、算法步骤
a.检查元素个数是否为偶数(ps:如果数组元素的个数为奇数,不满足条件);
b.判断按位异或整个数组元素的值是否不为0(ps:假如得到0,那么表示该数组中的元素全都成对出现);
c.计算出按位异或的结果中最右边为1的十进制数字(ps:只有该位为1,其他位都是0);
d.如果数组元素按位与c的结果等于c,则按位异或这个新数组的元素可以得到一个单独出现的数字;
e.如果数组元素按位与c的结果不等于c,则按位异或这个新数组的元素可以得到一个单独出现的数字。
4、源代码
扫描二维码关注公众号,回复:
54551 查看本文章
#define _CRT_SECURE_NO_WARNINGS 1 /* * Copyright (c) 2018, code farmer from sust * All rights reserved. * * 文件名称:AppearNumTwice.c * 功能:一个数组中只有两个数字出现一次, * 其他所有数字都出现了两次,找出这两个数字 * * 当前版本:V1.0 * 作者:sustzc * 完成日期:2018年4月20日12:13:47 */ # include <stdio.h> # include <assert.h> /* * 函数名称:FindOneNum * * 函数功能:找出一组数据中单独出现的数字 * * 入口参数:pArr, len * * 出口参数:ret * * 返回类型:int */ int FindOneNum(int * pArr, int len) { int i = 0; int ret = 0 ; assert(NULL != pArr); for (i=0; i<len; i++) { ret ^= pArr[i]; } return ret; } /* * 函数名称:JudgeRightOne * * 函数功能:判断数组中右边第一次出现1 * * 入口参数:pArr, len * * 出口参数:value * * 返回类型:int */ int JudgeRightOne(int * pArr, int len) { int value = FindOneNum(pArr, len); assert(NULL != pArr); //value &= ~(value - 1); value &= (-value); return value; } /* * 函数名称:FindTwoNum * * 函数功能:找出一组数据中单独出现的数字 * * 入口参数:pArr, len, first, second * * 出口参数:0 or 1 * * 返回类型:int */ int FindTwoNum(int * pArr, int len, int * first, int * second) { int i = 0; int bit = JudgeRightOne(pArr, len); int flag = FindOneNum(pArr, len); assert((NULL != pArr) && (NULL != first) && (NULL != second)); for (i=0; i<len; i++) { //右边第一次出现1 if(((bit == (pArr[i] & bit)) && (0 != flag))) { *first ^= pArr[i]; } else if (((bit != (pArr[i] & bit)) && (0 != flag))) { *second ^= pArr[i]; } else { return 0; } } return 1; } /* * 函数名称:OutputArray * * 函数功能:输出数组元素 * * 入口参数:pArr, len * * 出口参数:void * * 返回类型:void */ void OutputArray(int * pArr, int len) { int i = 0; assert(NULL != pArr); for (i=0; i<len; i++) { printf("%d ", pArr[i]); } printf("\n"); return; } int main(void) { int first = 0; int second = 0; int arr[] = {1,4,1,6,8,6}; int len = sizeof(arr) / sizeof(int); if (0 == (len%2)) { printf("数组元素为:\n"); OutputArray(arr, len); printf("单独出现两次的数字为:\n"); if (!FindTwoNum(arr, len, &first, &second)) { printf("没找到!\n"); } else { printf("%d %d\n", first, second); } } else { printf("数组元素为:\n"); OutputArray(arr, len); printf("没找到,请检查数组个数!\n"); } return 0; }
5、输出结果