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