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

需求

  找出数组中重复的数字。

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

运行结果:

猜你喜欢

转载自www.cnblogs.com/huangwenhao/p/11163002.html