• (python)剑指Offer:数组中重复的数字


    问题描述

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

    解题思路

    1、判断输入数组有无元素非法 
    2、从头扫到尾,只要当前元素值与下标不同,就做一次判断,numbers[i]与numbers[numbers[i]],相等就认为找到了重复元素,返回true,否则就交换两者,继续循环。直到最后还没找到认为没找到重复元素,返回false

    时间复杂度:O(n),空间复杂度:O(1)

    解题代码(python实现)

    #在长度为n的数组中,所有的元素都是0到n-1的范围内。 数组中的某些数字是重复的,但不知道有几个重复的数字,
    #也不知道重复了几次,请找出任意重复的数字。 例如,输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出为2或3
    def repeat_num(li):
        for index, value in enumerate(li):
            if index != value:
                li[index], li[value] = li[value], li[index]
            if index != value and value == li[value]:
                return li[index]
    
    li = [0, 1, 2, 3, 3, 4, 6, 4]
    print(repeat_num(li))
    

    扩展:

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

    思路:

    采用二分法查找,时间复杂度为 O(nlogn)

    在数字 1~n 中取中间值 m = (1+n) / 2, 此时数字包括 1~m, m+1~n 两段;
    遍历数组,获得数字 1~m 的个数;
    如果数字 1~m 的个数大于 m,说明 1~m 这一段内肯定有重复数字,那么在这一段内继续取中间值比较;
    如果数字 1~m 的个数等于 m,这一段不一定有重复数字,比较后一段;
    如果数字 1~m 的个数小于 m,说明 m+1~n 这一段一定有重复数字,在后一段取中间值比较;
    按照上述方法一直取中间值比较,直到只剩一个数字且这个数字出现次数超过 1 ,该数字即为重复数字

    class solution():
        def duplicate(self,numbers):
            if numbers == []:
                return False
            length = len(numbers)
            start = 1
            end = length - 1
            while end >= start:
                middle = (end - start)//2 + start
                count = self.countNum(numbers, length, start, middle)
                if end == start:
                    if count > 1:
                        return True
                    else:
                        break
                if count > middle - start + 1:
                    end = middle
                else:
                    start = middle + 1
            return False
    
        def countNum(self, numbers, length, start, end):
            count = 0
            for i in range(length):
                if numbers[i] < 1 or numbers[i] > length:
                    return False
                if start <= numbers[i] <= end:
                    count += 1
            return count
    
    ss = solution()
    print(ss.duplicate([4,2,3,1,2,5]))
    print(ss.duplicate([4,2,3,1]))
    

      这种方法虽然不需要辅助空间O(n),但是后面每半个区间都需要遍历整个数组,函数countNum将被调用O(logn)次,每次需要O(n)的时间,因此总的时间复杂度是O(nlogn),空间复杂度为O(l)。相当于用时间换空间了。
      现在来总结下关于数组中重复数字的问题,利用辅助空间的话,时间和空间复杂度都是O(n);利用下标于数字对应关系的话时间复杂度是O(n),空间复杂度是O(l),但是需要改变数组;利用二分查找类似思路的方法,时间复杂度是O(nlogn),空间复杂度O(l),所以要问清楚面试官他想要空间效率高的呢?还是时间效率高的呢?能不能改变数组呢?一方面体现交流能力,一方面能最快的写出答案。

  • 相关阅读:
    python中的time模块
    CSS 布局
    8 Function类型
    2 node 核心
    1 node 简介
    13 对象
    JS 算法一
    JS 模块化
    1 谈谈section标签
    JS 练习一
  • 原文地址:https://www.cnblogs.com/tianqizhi/p/9863530.html
Copyright © 2020-2023  润新知