找出数组中重复的数字

 

题目一:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7,的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数组2或者3。(n个元素,n种可能的取值)

解法一:先对数组进行排序,然后再查找排序后的数组中的重复元素

def selectedSort(lis):
for i in range(0, len(lis)):
        minVal = lis[i]
        minInd = i
        #找出最小的元素
        for j in range(i+1,len(lis)):
            if minVal>=lis[j]:
                minVal=lis[j]
                minInd=j
        #交换
        lis[minInd]=lis[i]
        lis[i]=minVal
    return lis
lis=[8,5,3,3,7,6,3,9,1,8]
lis_order=selectedSort(lis)
print(lis)

 

解法二:开辟一个新数组B,每次扫描源数组A中的元素,如果不在B中,就加入B中,如果在B中,就找到一个重复的元素

lisA=[8,5,3,3,7,6,3,9,1,8]
def findDuplicates(lisA):
    lisB = []
    for i in lisA:
        if i in lisB:
            print("找到一个重复的元素:%d"%i)
            break
        else:                   #当前扫描的元素不在lisB中,就加入到lisB中
            lisB.append(i)
            continue
findDuplicates(lisA)

 

解法三:因为列表总共有n个元素,所有元素可能取到的元素有0~n-1,共n种。如果不存在重复的数字,那么排序后数字i将会出现在下标为i的位置。现在让我们重新扫描数组,

  • 当扫描到下标为i的数字时,首先比较这个数字(记为m)与i是否相等:
    • 如果是,继续扫描下一个元素,
    • 如果不是,则再拿它与第m个数字比较:
      • 如果它和第m个数字相同,就找到了一个重复的元素;
      • 如果不同,就将m与第m个数字互换。接下来继续重头开始,重复换这个比较。

 

lisA=[8,0,2,3,7,6,4,2,1,5]
def findDuplicates(lisA):

    i=0
    while i <len(lisA) and lisA!=[]:
        m = lisA[i]
        if m == i:    
            i += 1
        else:
            if m == lisA[m]:
                print('找到一个重复的元素:%d' % m)
                break
            else:
                temp = lisA[i]
                lisA[i] = lisA[m]
                lisA[m] = temp
                i = 0

findDuplicates(lisA)

 


 

题目二:

在一个长度为n+1的数组里的所有数字都在1~n范围内,所以数字中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或3。(n+1个元素,n种可能的取值)

解法一:同上题解法二,开辟一个大小为n+1的新数组

解法二:避免使用O(n)的辅助空间。我们把取值空间[1,n]从中间的数字m分为两部分,前面一部分为1~m,后面一部分为m+1~n。如果数组中元素落在前面一部分的元素个数多于m个,那么数组中重复的元素一定落在前半区间;否则,数组中重复的元素一定落在后半区间。然后,我们可以继续将包含重复元素的区间一分为二,直到找到一个重复的元素。

lisA=[8,1,2,3,7,6,7,4,9,5,10]

def findDuplicates(lisA):
    """找到重复元素,返回True;否则,返回False"""
    low=1
    high=len(lisA)-1

    while low<=high:
        mid=(low+high)//2

        #统计数组中落在前半部分区间中的元素的个数
        count_low=0
        for i in lisA:
            if i in range(low,mid+1):
                count_low+=1

        #判断落在长度为1的区间中的数组元素个数
        if high==low:
            if count_low>1:                 #如果大于1,则找到重复的元素
                return low
            else:
                break

        #比较前半部分区间长度与落在该区间内元素的个数,决定将前半部分/后半部分区间继续一分为二
        if count_low>(mid-low+1):
            high=mid
        else:
            low=mid+1

    return False

print(findDuplicates(lisA))

 

 

posted @ 2019-07-16 15:17  割肉机  阅读(7579)  评论(0编辑  收藏  举报