查找数组中重复的数字(一)

需求

  找出数组中重复的数字。

  在一个长度为n的数组里的所有数字都在0~n-1的范围内,数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。(不要求输出所有的重复数字,找到其中之一即可)

 

分析

思路一:

对输入的数组先进行排序,然后从头到位遍历排序好的数组,当出现第一个数组下标与存储的值不一样的(array[i] != i),就说明找到了重复数字。排序需要的时间复杂度为O(nlgn)。见示例代码中的findRepeatNumberWithSort

 

思路二:

使用一个辅助的数组,长度为n,如:tmp[n],然后开始遍历原始数组

1.如果数组中出现数字x,就判断数组下标为x的节点是否还是初始值0,即tmp[x]是否为0;

2.如果tmp[x] == 0,就标记为1,然后继续遍原始数组的下一个元素,继续步骤1;

3.如果tmp[x] != 0,说明之前已经表标记为1了,即之前已经出现过这个相同的元素,即已经找到重复数字了。

这种方法由于需要使用一个长度为n的辅助数组,空间复杂度为O(n)。见示例代码中的findRepeatNumberWithExArray。

 

思路三:

不使用辅助数组,也不用提前排序的方法,暂且称为动态排序法吧。

先考虑另外一种情况:

假如一个排序好的长度为n的数组,数组中的数字为0~n-1,并且没有重复数字,那这个数组中存储的数字应该是:array[0]=0,array[1]=1,array[2]=2....array[n-1]=n-1。也就是说数组的下标应该是跟存储的值是一样的。

回到这个需求:

如果数组中的数字有重复,说明肯定存在array[i]=i并且array[j]=i(可能还有array[k]=i,array[l]=i.....)。

大前提了解了,下面开始按照这个思路查找重复数字。

从原始数组第0个位置开始遍历,

1.假如 array[i] == i 说明,这个位置放置了对的数值,然后开始查检查array[i+1];

2.假如 array[i] != i ,假如值为x,判断array[x]是不是等于x,如果是说明array[i]和array[x]都等于x,查找到了2个x,说明任务结束,可以返回结果了;

3.假如 array[i] != i ,假如值为x,判断array[x]是不是等于x,如果不是,就把array[i]跟array[x]的数字交换,使得array[x]=x,这样x就放到了array[x]的位置上,也就是找到对应的位置了,然后继续步骤1,判断当前的array[i]的数字。

通过这种思路,可以看到不需要提前对数组进行排序,只需要在判断的时候顺便排序即可,只需一个循环,时间复杂度是O(n),由于只需要使用一个辅助的空间用于交换数据,空间复杂度是O(1)【ps:甚至可以不用辅助空间来交换两个数字】。

见示例代码中的findRepeatNumberDynamicSort。

 

c++示例代码如下:

  1 #include <iostream>
  2 #include <algorithm>
  3 
  4 using namespace std;
  5 const int ARR_LENGTH = 7;
  6 
  7 /************************************************************************/
  8 /* @brief 使用sort查找数组中其中一个重复数字
  9 /* @param arr数组
 10 /* @param length数组长度
 11 /* @return 数组中其中一个重复的数字,-1表示没找到
 12 /************************************************************************/
 13 int findRepeatNumberWithSort(int* arr, const int length)
 14 {
 15     int result = -1;
 16 
 17     //入参有问题直接返回,少于2个数字肯定没有重复的
 18     if (!arr || length < 2)
 19     {
 20         return result;
 21     }
 22 
 23     sort(arr, arr + length);
 24     for (int i = 0; i < length; ++i)
 25     {
 26         if (arr[i] != i)
 27         {
 28             result = arr[i];
 29             break;
 30         }
 31     }
 32     return result;
 33 }
 34 
 35 /************************************************************************/
 36 /* @brief 使用额外的辅助数组查找数组中其中一个重复数字
 37 /* @param arr数组
 38 /* @param length数组长度
 39 /* @return 数组中其中一个重复的数字,-1表示没找到
 40 /************************************************************************/
 41 int findRepeatNumberWithExArray(int* arr, const int length)
 42 {
 43     int result = -1;
 44 
 45     //入参有问题直接返回,少于2个数字肯定没有重复的
 46     if (!arr || length < 2)
 47     {
 48         return result;
 49     }
 50 
 51     //一个临时的辅助数组
 52     int *tmpArr = new int[length];
 53     memset(tmpArr, 0, sizeof(int)*length);
 54 
 55     for (int i = 0; i < length; ++i)
 56     {
 57         if (tmpArr[arr[i]] != 0)
 58         {
 59             result = arr[i];
 60             break;
 61         }
 62         else
 63         {
 64             tmpArr[arr[i]] = 1;
 65         }
 66     }
 67     delete[] tmpArr;
 68     tmpArr = nullptr;
 69     return result;
 70 }
 71 
 72 /************************************************************************/
 73 /* @brief 不使用辅助数组,动态排序法查找重复数字
 74 /* @param arr数组
 75 /* @param length数组长度
 76 /* @return 数组中其中一个重复的数字,-1表示没找到
 77 /************************************************************************/
 78 int findRepeatNumberDynamicSort(int* arr, const int length)
 79 {
 80     int result = -1;
 81 
 82     //入参有问题直接返回,少于2个数字肯定没有重复的
 83     if (!arr || length < 2)
 84     {
 85         return result;
 86     }
 87 
 88     int i = 0;
 89     while (i < length)
 90     {
 91         int key = arr[i];
 92         //如果数组下标和存储的值相同(arr[i]等于i),说明这个值已经放到了它应该在的地方(即已经排序到了正确的位置),继续数组中的下一个值
 93         if (key == i)
 94         {
 95             ++i;
 96         }
 97         else
 98         {
 99             //由于key跟i不相同,并且arr[key],arr[i]这两个位置都存储了同一个值key,说明找到了相同的数字,结束循环,返回结果
100             if (arr[key] == key)
101             {
102                 result = key;
103                 break;
104             }
105             //让arr[i]和arr[key]的值交换,使得arr[key]这个位置存放他该放的值,即arr[key]等于key
106             else
107             {
108                 arr[i] = arr[key];
109                 arr[key] = key;
110             }
111         }
112     }
113     return result;
114 }
115 
116 int main()
117 {
118     int arr[ARR_LENGTH] = { 2,3,1,0,2,5,3 };
119     cout << "原始数据:" << endl;
120 
121     for (int i = 0; i < sizeof(arr) / sizeof(int); ++i)
122     {
123         cout << arr[i] << "  ";
124     }
125 
126     int repeat = findRepeatNumberWithSort(arr, ARR_LENGTH);
127     cout << "\n\n排序法查找重复数字:" << repeat << endl;
128 
129     repeat = findRepeatNumberWithExArray(arr, ARR_LENGTH);
130     cout << "\n辅助数组法查找重复数字:" << repeat << endl;
131 
132     repeat = findRepeatNumberDynamicSort(arr, ARR_LENGTH);
133     cout << "\n动态排序法查找重复数字:" << repeat << endl;
134 
135     return 0;
136 }

 

运行结果:

 

posted @ 2019-07-10 11:50  纯情小浩浩  阅读(420)  评论(0编辑  收藏