剑指offer二刷——数组专题——数组中重复的数字

题目描述

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

我的想法

最开始想到的是用“字典”,依次记录每个数字出现的次数,这就要遍历数组并且创建字典,感觉空间上占用较大。

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        dic={}
        for i in numbers:
            if i in dic:
                duplication[0]=i
                return True
            else: dic[i]=1
        return False

  时间复杂度o(n),空间复杂度o(n)

 

然后想到用数组代替字典,因为数组内所有数字都在0到n-1的范围内,那么我可以创建一个大小为n的数组a,初始值都为0,利用数组下标记录a[i]是否为0。如果a[i]==0,那么说明该数字是第一次遍历到,令a[i]=1;如果a[i]==1,那么说明该数字是第二次遍历到,该数字重复,令duplication[0]=i,返回True;如果遍历完全后没有return False,那么就return True。

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        if len(numbers)==0: return False
        a=[0]*len(numbers)
        for i in numbers:
            if not a[i]: a[i]=1
            else:
                duplication[0]=i
                return True
        return False

  时间复杂度o(n),空间复杂度o(n)

然后我觉得以上两种方法,空间复杂度都为o(n),应该还有空间复杂度更小的解法。但我想不出来了。

 

官方解法

也是利用数组下标的性质,但是不是新建一个数组,而是利用指针。i 从0的位置开始,一定要找到每个 i 对应的数字,即numbers[i]=i,才能继续下一个,如果交换过程中发现已经是numbers[i]=i,那么当前要交换的数字就是重复的数字。

 1 # -*- coding:utf-8 -*-
 2 class Solution:
 3     # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
 4     # 函数返回True/False
 5     def duplicate(self, numbers, duplication):
 6         # write code here
 7         if not numbers or len(numbers)==0:return False
 8         for i in range(len(numbers)):
 9             while i!=numbers[i]:
10                 if numbers[i]==numbers[numbers[i]]:
11                     duplication[0]=numbers[i]
12                     return True
13                 # swap
14                 # numbers[i],numbers[numbers[i]] = numbers[numbers[i]],numbers[i]不可行
15                 tmp=numbers[i]
16                 numbers[i]=numbers[numbers[i]]
17                 numbers[tmp]=tmp
18         return False

   时间复杂度o(n),空间复杂度o(1)

上述代码官方给的步骤:

    1. 设置一个指针i指向开头0,

    2. 对于arr[i]进行判断,如果arr[i] == i, 说明下标为i的数据正确的放在了该位置上,让i++

    3. 如果arr[i] != i, 说明没有正确放在位置上,那么我们就把arr[i]放在正确的位置上,也就是交换
      arr[i] 和arr[arr[i]]。交换之后,如果arr[i] != i, 继续交换。

    4. 如果交换的过程中,arr[i] == arr[arr[i]],说明遇到了重复值,返回即可。
      如下图:

                       
 

使用内置函数的解法

使用set函数可以删除无序数组中重复的数字。 https://www.runoob.com/python/python-func-set.html

使用 collections.Counter.most_common(1) 可以找到数组中重复最多的数字。https://blog.csdn.net/qwe1257/article/details/83272340

 1 # -*- coding:utf-8 -*-\
 2 from collections import Counter
 3 class Solution:
 4     # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
 5     # 函数返回True/False
 6     def duplicate(self, numbers, duplication):
 7         # write code here
 8         if len(numbers)==0 or not numbers:return False
 9         if len(numbers)==len(set(numbers)):return False
10         duplication[0]=Counter(numbers).most_common(1)[0][0]
11         return True

 

 

 

 

 
 
 
 
posted @ 2020-08-17 16:31  Olebaba  阅读(103)  评论(0编辑  收藏  举报