問題描述
在長度為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),所以要問清楚面試官他想要空間效率高的呢?還是時間效率高的呢?能不能改變數組呢?一方面體現交流能力,一方面能最快的寫出答案。
