首页 > 代码库 > 求重复数算法思路

求重复数算法思路

关于求重复数,我们先来看看两道常见的题

1、有101个数,为[1,100]之间的数,其中一个数是重复的,如何寻找这个重复的数,其时间复杂度和空间复杂度是多少?

2、1-N(N最大32000,且未知),内存只有4K,找出其中的重复数

找重复数,基本的思路有四个

  1. 第一种思路,建立布尔数组,用每一位的下标来表示某个数的值,用每一位的值来表示该数是否重复。这种思路适合数组中最大数不大的情况。一旦最大数过大,那么我们需要建立的布尔数组便会过大,这时候空间消耗就非常大了,有可能会超出内存需求时间复杂度为 o(n),空间复杂度不稳定。
  2. 第二种思路,进行 hash 运算或取余运算,利用冲突来找出相同数。这种思路比较简单,对空间和时间消耗都不大,但是实现比较麻烦,因为要判断冲突,解决冲突。时间复杂度为 0(n),空间复杂度为 0(n)
  3. 第三种思路,根据高位或低位,采用二分或者四分递归找出重复值。适用于数据量过大的情况。时间复杂度为 0(nlogn),空间复杂度 0(1)
  4. 第四种思路,可以先对数组进行堆排序或者快速排序,然后遍历排过序的数组。时间复杂度为 0(nlogn),空间复杂度 0(n)。

首先看第一题,

  1. 采用第一种思路的话,我们要建立一个大小为100的布尔数组b,并且都初始化为 false 。然后对待排序的数组进行遍历,假如数组前四个元素的值为{62,53,88,62},那么,我们就将 b[62]=true , b[53]=true , b[88]=true ,当进行第四次赋值的时候,因为 b[62]之已经赋过值了,对再次赋值时经判断其值为 true,那么,62 便是我们要找的重复数。
  2. 采用第二种思路的话,假设待处理数组a 长度为 n ,那么我们可以新建一个长度为n的对象数组b,把数组a中的每一个元素对 n 进行取余结果为i,然后将该元素储存到下标为 b[i]。采用链表的方式解决冲突。当发生冲突的时候,检查冲突位置链表内是否有这个元素。如果有的话,说明它为重复值。
  3. 第三种思路,可以根据数组中每个值最高位为0还是1,进行二分。然后循环递归一直到最低位相等。相等的两个数便是重复数。
  4. 第四种思路,对这101个数进行堆排序或快速排序,然后遍历排好序的数组便可得到相等数。

接下来来看第二个问题,因为对空间大小有要求,解决就稍微复杂一点。

  1. 采用第一个思路:要建立布尔数组,每一个元素占 1bit,(1*32000)/(8*1024)=3.9KB,正好在4K 之内,所以第一种思路有效。
  2. 采用第二种思路:由于数组个数未知,所以不能判断可行性(元素个数超过1024个便无法处理了)。
  3. 采用第三中思路:假设所有的数据都储存在硬盘上,一次读一个或者多个(4K内存范围内),分别按最高位或最高两位等进行2分或多分。然后循环递归,再2分或多分已被分的数组,知道找到一样的数。
  4. 采用第四种思路:因为不知道数组大小,不能判断可行性(元素个数超过1024个便无法处理了)

对比这四个思路,各有各的优势和劣势,也各有各的使用场景。实际使用时一定要灵活变通。

求重复数算法思路