问题描述:★整型数组中,只有两个数字只出现了一次,其余都是成对出现的,输出这两个数。
方法:①最直接的方法是双层循环遍历(暴力输出),通过设置标志位控制输出,但此种做法的时间复 杂度为O(n^2),所以便利程度最低,在此不做演示。
②第二种方法是建立像哈希表样的形式,通过原数组的地址映射作为新建数组的下标,通过相应 的新建数组的下标值,让相同数字对应相同的新数组的同一位置的值不断自增,最终输出新建 数组值为1的下标(该下标就是原数组中对应的数字)。此种方法的时间复杂度为0(n),因为 只需遍历一次即可。
③还有一种方法是利用异或运算的性质。一组数中只找一个出现一次的数字,我们都知道用异或 运算很简单,而找两个只出现一次的数字用异或来做的难点就仅仅在于如何把这两个只出现一 次数字异或的最终结果拆开。此种方法的时间复杂度为0(n),应为首选之策。
★建立新数组(类哈希表)方法的C代码实现
#include<stdio.h> #include<stdlib.h> #include<assert.h> //调用函数 void first_num(int * str) { assert(str); //断言,判断传进的数组指针是否有效,用以抛出异常。 int asc[10] = { 0 }; //创建一个十个元素的数组,因为原数组元素的大小都只为0~9的元素,可根据需要自行设定大小。 int i = 0; for (i = 0; i<10 ; i++) { asc[str[i]]++; //将原数组的元素作为新建数组的下标,并自增。如果原数组有相同元素,说明在新建数组对应的位置处的值会不断加1。 } printf("出现一次的两数为:\n"); for (i = 0; i<10; i++) { if (asc[str[i]] == 1) //输出条件,只要新建数组的值仍为1,说明原数组中该元素只有一个。 { printf("%d ", str[i]); } } } //主函数 int main() { int arr[10] = {1,2,3,4,5,1,2,6,3,4}; first_num(arr); printf("\n"); system("pause"); return 0; }
★异或方法的C代码实现
#include <stdio.h> #include<stdlib.h> int find_one_bit(int num) //约定寻找二进制中的某一位为1的位 { int bit = 0; while (num) { if (num & 1 == 1) return bit; bit++; num = num >> 1; } return -1; } void find_num(int arr[], int size, int *p1, int *p2) { int tmp = 0; int i = 0; int pos = 0; for (i = 0; i < size; i++) { tmp ^= arr[i]; //tmp保存的最终结果为不同的两个数字异或的结果 } pos = find_one_bit(tmp); for (i = 0; i < size; i++) { if (1 & (arr[i] >> pos)) //约定二进制位中同一位置是否为1,用以分组数字,因为某一位为1时,由异或的结果可知必定一个数字该位为0,另一个为1。0(0==*p1)与任何数字异或仍为该数本身。 *p1 ^= arr[i]; else *p2 ^= arr[i]; } } //主函数 int main() { int arr[] = {1,2,3,4,5,1,2,6,3,4}; int size = sizeof(arr) / sizeof(arr[0]); int num1 = 0; int num2 = 0; find_num(arr, size, &num1, &num2); //num1,num2必须传进地址,否则只是修改了形参而并不影响主函数的值,num1,num2仍为初始化的0。 printf("%d %d\n", num1, num2); system("pause"); return 0; }