编程练习:找“单身狗“(三种解题法(不含暴力法))
创始人
2024-05-11 10:02:50
0

目录

一.问题描述

二. 方法一:排序法

题解代码: 

三.方法二:位运算法

第一步:

第二步:

第三步:

题解代码:

方法三:顺序表记录法

第一步:

第二步:

第三步:

第四步:

题解代码:


一.问题描述

数组arr中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。(数组元素个数假设为sz)函数返回一个两个元素的数组的首地址(数组在堆区上创建,该数组中存放数组arr中两个只出现了一次的数字)。

示例:

给定数组{4,2,3,6,7,8,9,10,12,5,2,3,6,7,11,9,10,12,4,5 }; 

函数返回的数组(首地址):[8,11];

题解接口定义:int* FindNum1(int* arr, int sz);

(函数返回一个存储查找结果的数组)

(sz为数组的大小)

二. 方法一:排序法

注意数组排好序后,当待查找的元素位于数组边界位置时的情况需要单独拎出来判断处理。

 

 

题解代码: 

//方法一:排序
int cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
int* FindNum1(int* arr, int sz)
{assert(arr);int* ptr = (int*)malloc(2 * sizeof(int)); //为存放查找结果的数组申请堆区上的空间if (ptr == NULL)                          //判断指针的有效性{perror("malloc failed\n");return NULL;} qsort(arr, sz, sizeof(int), cmp);         //用快排对数组进行排序int count = 0;                            //count用来记录找到了几个元素     if (arr[0] - arr[1])                      //先进行左边界判断{ptr[count++] = arr[0];}else if (arr[sz - 1] - arr[sz - 2])       //再进行后边界判断{ ptr[count++] = arr[sz - 1];}if (count == 2){return ptr;}int i = 0;                                //判断除边界外的元素是否满足情况for (i = 1; i < sz-1; i++){if (arr[i]-arr[i - 1] && arr[i]-arr[i + 1]){ptr[count++] = arr[i];if (count == 2){return ptr;}}}return ptr;
}

该方法的时间复杂度就是排序的时间复杂度:O(nlogn).

三.方法二:位运算法

数组元素的异或和:将数组所有元素进行异或运算得到的结果.

比如一个数组:[1,2,3,4],则该数组的异或和为:1^2^3^4.

注意异或运算满足交换律和结合律

第一步:

求数组arr的异或和NorSum:

	int i = 0;int NorSum = 0;                         //0异或x(x为任意值)结果为x,NorSum一定要初始化为0for (i = 0; i < sz; i++){NorSum ^= arr[i];                   //NorSum=x^y ,NorSum记录了x和y的不同位}

第二步:

记录NorSum的某一位1,把该为1记录于lowbit中,用于将数组的元素进行分组

该步骤有两种方法:

方法1:lowbit= NorSum&(-NorSum)

方法原理:假设x为正数,将x符号位变为1,其余位按位取反,这时得到-x的反码,-x的反码与x的每一位都不一样,这时-x的反码再加上1(这时会得到-x的补码),其最低位的0就会变为1,而-x的反码的最低位的0对应x最低位的1,所以 -x&x的结果就记录了x的最低位的1。

方法2:利用循环逐位去找NorSum的某一位1并记录其位置:

for (i = 0; i < 32; i++){if (NorSum & (1 << i)){lowbit= (1<

lowbit记录了NorSum最低位的1的位置。

我们采用方法1

第三步:

利用lowbit以按位与的方式对数组元素进行分组

	int Lowbit = NorSum &(-NorSum);          /*取出NorSum中的最低位,该最低位可以将arr中的数 分为两组*/                              //NorSum位数太多无法用于分组(位数多无法确定分组的 //可能性)int x = 0;int y = 0;                               //假设两个单独存在的数分别为x和yfor (i = 0; i < sz; i++)                 //利用和lowbit按位与的方式将数组元素分为两组{                                        //所有成对的数必定出现在同一组,x和y分别会位于不 //同组if ((Lowbit & (arr[i])) == 0)        //分别求两组数的异或和就可以得到x和y{ x ^= arr[i];}else{y ^= arr[i];}}

题解代码:

 

//方法二 位运算
//假设两个单独存在的数分别为x和y
int* FindNum2(int* arr, int sz)
{assert(arr);int* ptr = (int*)malloc(2 * sizeof(int)); //为存放查找结果的数组申请堆区上的空间if (ptr == NULL)                          //判断指针的有效性{perror("malloc failed\n");return NULL;}int i = 0;int NorSum = 0;                          //0异或x(x为任意值)结果为x,NorSum一定要初始化 //为0for (i = 0; i < sz; i++){NorSum ^= arr[i];                    //NorSum=x^y ,NorSum记录了x和y的不同位}int Lowbit = NorSum &(-NorSum);          /*取出NorSum中的最低位,该最低位可以将arr中的 //数分为两组*/                              //NorSum位数太多无法用于分组(位数多无法确定分 //组的可能性)int x = 0;int y = 0;for (i = 0; i < sz; i++)                 //利用和lowbit按位与的方式将数组元素分为两组{                                        //所有成对的数必定出现在同一组,x和y分别会位于 //不同组if ((Lowbit & (arr[i])) == 0)        //分别求两组数的异或和就可以得到x和y{ x ^= arr[i];}else{y ^= arr[i];}}ptr[0] = x;ptr[1] = y;return ptr;
}

该方法的时间复杂度是线性的:O(n)

方法三:顺序表记录法

 

第一步:

找到数组中的最大值和最小值:

	int max = arr[0];for (i = 1; i < sz; i++){if (arr[i] > max){max = arr[i];}}int min = arr[0];for (i = 1; i < sz; i++){if (arr[i] < min){min = arr[i];}}

第二步:

用最大值和最小值去创建顺序表tablePos和tableNeg分别用于记录数组中正数和负数的出现次数

	int* tablePos = (int*)calloc(max+1,sizeof(int));if (NULL==tablePos){perror("malloc failed\n");return NULL;}int* tableNeg = (int*)calloc(Abs(min) + 1, sizeof(int));if (NULL==tableNeg){perror("malloc failed\n");return NULL;}

第三步:

遍历数组将各元素出现次数记录在表中

	for (i = 0; i < sz; i++){if (arr[i] >= 0){tablePos[arr[i]]++;}else{tableNeg[Abs(arr[i])]++;}}

第四步:

遍历顺序表找到值为1的元素。

	ptr是记录单身数的数组int count = 0;                     count记录找到的单身数的个数for (i = 0; i < (max + 1); i++){if (1 == *(tablePos+i)){ptr[count++] = i;if (2 == count){free(tablePos);free(tableNeg);return ptr;}}}for (i = 0; i < Abs(min); i++)      Abs是求绝对值的函数{if (1==tableNeg[i]){ptr[count++] = -i;if (2==count){free(tablePos);free(tableNeg);return ptr;}}}

题解代码:

//方法三:顺序表记录法
int Abs(int num)                              //封装一个求绝对值的函数
{return num >= 0 ? num : -num;
}
int* FindNum3(int* arr, int sz)
{assert(arr);int* ptr = (int*)malloc(2 * sizeof(int)); //为存放查找结果的数组申请堆区上的空间if (NULL==ptr)                            //判断指针的有效性{perror("malloc failed\n");return NULL;}int i = 0;int max = arr[0];for (i = 1; i < sz; i++){if (arr[i] > max){max = arr[i];}}int min = arr[0];for (i = 1; i < sz; i++){if (arr[i] < min){min = arr[i];}}int* tablePos = (int*)calloc(max+1,sizeof(int));if (NULL==tablePos){perror("malloc failed\n");return NULL;}int* tableNeg = (int*)calloc(Abs(min) + 1, sizeof(int));if (NULL==tableNeg){perror("malloc failed\n");return NULL;}for (i = 0; i < sz; i++){if (arr[i] >= 0){tablePos[arr[i]]++;}else{tableNeg[Abs(arr[i])]++;}}int count = 0;for (i = 0; i < (max + 1); i++){if (1 == *(tablePos+i)){ptr[count++] = i;if (2 == count){free(tablePos);free(tableNeg);return ptr;}}}for (i = 0; i < Abs(min); i++){if (1==tableNeg[i]){ptr[count++] = -i;if (2==count){free(tablePos);free(tableNeg);return ptr;}}}free(tablePos);free(tableNeg);return ptr;
}

该方法的时间复杂度也是线性的:O(n)

 相似的题目leetcode链接:645. 错误的集合 - 力扣(Leetcode)

 

 

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...