在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3,那么对应的输出是重复的数字2或者3。
第一种方式:使用遍历寻找的方式进行寻找,
#include <stdio.h>
void find_same_number(int arr[],int len){
int i=0;
int j=0;
for(j=0;j<len-1;j++){
for(i=j+1;i<len;i++){
if(arr[j]==arr[i]){
printf("same number have %d\n",arr[j]);//如果想return怎么办
}
}
}
}
int main(int argc, char const *argv[])
{
int arr[7]={2,3,1,0,2,5,3};
int len=sizeof(arr)/sizeof(arr[0]);//计算数组长度
find_same_number(arr,len);
return 0;
}
第二种:利用好这一条件:所有数字都在0~n-1的范围内。
以空间换时间使用哈希表来实现,时间和空间复杂度都是O(n),核心思想:通过交换把每个元素归位到以该元素为数组下标的位置上
假设数组是 s[0]!=0 然后和s[3]进行交换,交换结束后数组的第三个位置上正好是3 ,s[1]=1,s[2]=2,交换后s[3]=3发现s[4]=3!=4这是就说明有重复的数字出现了 返回这个数字即可。
#include <stdio.h>
#include <string.h>
//
int find_same_num(int *p,int len){
//入参检查
if(p==NULL || len < 0){
printf("入参为空请检查!%s-%s-[%d]\n",__func__,__LINE__);
return -1;
}
int temp=0;//定义中间变量
int flag=0;
//外层循环遍历数组内
for(int i=0; i<len ;i++){
flag=0; //定义一个标志位
//内层寻找下标与数组值不相同的数
while (p[i]!=i)
{
if(p[i]==p[p[i]]){//这个条件是一般想不到的,值得学习
//return p[i];
flag=1;
printf("%d\n",p[i]);
break;
}
temp=p[i];
p[i]=p[temp];
p[temp]=temp;
}
}
if(flag==0){
return -1;
}
}
int main(int argc, char const *argv[])
{
int arr[7]={2,3,1,0,2,5,3};
int len=sizeof(arr)/sizeof(arr[0]);
if(find_same_num(arr,len)==-1){
printf("该数组没有重复的数字\n");
}
return 0;
}
第三种方式:
使用二分法去查找该数组中是否存在重复的数字,先将整个数组中的数字分成一半一半,判断两个元素的个数,如果大于范围,则重复的数字就在整个范围之内。例如1-3范围内有4个数,就说明至少有一个重复的数字,就一直这样二分即可
#include <stdio.h>
int find_numbers(const int *number,int length){
if(number == NULL || length == 0){
printf("入参有误,请检查 \n");
return -1;
}
for(int i=0;i<length;i++){
if(number[i]>length-1 || number[i]<=0){
printf("所测数组有问题!\n");
return -1;
}
}
printf("%d\n",length);
int start =1;
int end=length-1;
int middle = 0;//右移一位相当于除以2
printf("%d\n",middle);
int count = 0;
int i=0;
while (end >= start){
middle = ((start + end)>>1) ;
count = 0;
for(i=0;i<length;i++){
if(number[i] >= start && number[i] <= middle){
count++;
}
}
if(end <= start){
if(count > 1){
printf("%d\n",start);
return -1;
}
}
if(count > (middle - start + 1)){
end = middle;
}else{
start = (middle + 1);
}
}
return 0;
}
int main(int argc, char const *argv[])
{
int number[8]={2,3,5,4,3,2,6,7};
int length =sizeof(number)/sizeof(number[0]);
find_numbers(number,length);
return 0;
}
第四种方式:通过异或的方式实现:
#include <stdio.h>
int find_num(const int *num){
int i=0;
int j=0;
for(i=0;i<8-1;i++){
for(j=i+1;j<8;j++){
if((num[i] ^ num[j])==0){
printf ("num =%d\n",num[i]);
break;
}
}
}
}
int main(int argc, char const *argv[])
{
int num[8] = {2,3,5,4,3,2,6,7};
int ret=find_num(num);
printf("ret = %d\n",ret);
int i=0;
for(i=0;i<8;i++){
printf("%d\n",num[i]);
}
return 0;
}