• 普通方法,空间复杂度是O(n)
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        hashmap = {}
        for i,j in enumerate(numbers):
            if j in hashmap:
                duplication[0] = j
                return True
            hashmap[j] = i
        return False
  • 利用数组的特性,空间复杂度是O(1)

    题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。

分析题目,由于数字都在[0,n-1]的闭区间内,所以可以遍历数组,用第i个数的数值作为它的索引,再将该索引对应的数值加n。(代码第7行和13行)当另一个相同数字出现时,它的索引指向的数字因为之前加过n所以一定会大于等于n。此时即可返回该数字。(10行)

需要考虑的是,由于有些数字的值是加过n的,当遍历到该数字时,用数值做索引会超出范围,此时需要将该数值减n得到它的初始值,由初始值作为索引。

相应的,如果题目是:

在一个长度为n的数组里的所有数字都在1到n的范围内。

我们可以修改条件,把+n换成*(-1),index变为abs[num]-1

class Solution:

    def duplicate(self, numbers, duplication):
        # write code here
        n = len(numbers)
        for i in range(n):
            index = numbers[i]
            if index >= n:
                index -= n
            if numbers[index] >= n:
                duplication[0] = index
                return True
            numbers[index] = numbers[index] + n
        return False
  • 书上的做法,重排数组
    class Solution:
      # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
      # 函数返回True/False
      def duplicate(self, numbers, duplication):
          # write code here
          if not numbers or len(numbers)==0:
              return False
          for i in range(len(numbers)):
              while i!=numbers[i]:
                  if numbers[i] == numbers[numbers[i]]:
                      duplication[0] = numbers[i]
                      return True
                  temp = numbers[i]
                  numbers[i] = numbers[temp]
                  numbers[temp] = temp
          return False
    

扩展题目描述:
  在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改输入的数组。

  • 利用二分法,时间复杂度是O(nlogn),空间复杂度是O(1)

    class Solution:
      # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
      # 函数返回True/False
      def duplicate(self, numbers):
          # write code here
          if not numbers:
              return False
          start = 1
          end = len(numbers) - 1
          while start <= end:
              mid = start + (end - start )//2
              count = self.countrange(start,mid,numbers)
              if start == end:
                  if count > 1:
                      return start 
                  else :
                      break
              if count > (mid - start + 1):
                  end = mid
              else:
                  start = mid + 1
          return -1
    
      def countrange(self,start,end,numbers):
          count = 0
          if not numbers:
              return False
          for i in numbers:
              if start <= i <= end:
                  count = count + 1
          return count