zoukankan      html  css  js  c++  java
  • (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),所以要问清楚面试官他想要空间效率高的呢?还是时间效率高的呢?能不能改变数组呢?一方面体现交流能力,一方面能最快的写出答案。

  • 相关阅读:
    UVA 254 Towers of Hanoi
    UVA 701 The Archeologists' Dilemma
    UVA 185 Roman Numerals
    UVA 10994 Simple Addition
    UVA 10570 Meeting with Aliens
    UVA 306 Cipher
    UVA 10160 Servicing Stations
    UVA 317 Hexagon
    UVA 10123 No Tipping
    UVA 696 How Many Knights
  • 原文地址:https://www.cnblogs.com/tianqizhi/p/9863530.html
Copyright © 2011-2022 走看看