在上一篇博客中《劍指Offer》-- 題目一:找出數組中重複的數字(Python多種方法實現)中,其實能發現這類題目的關鍵就是一邊遍歷數組一邊查知足條件的元素。python
而後咱們在博客用最複雜的方式學會數組(Python實現動態數組)這篇博客中介紹了數組這一結構的本質,並本身動手實現了一個動態數組。面試
今天咱們介紹一下另外一道來自《劍指Offer》的關於數組的面試題——不修改數組找出重複的數字。算法
題目二:不修改數組找出重複的數字shell
給定一個長度爲 n+1 的數組裏的全部數字都在 0∼n 的範圍內,因此數組中至少有一個數字是重複的。數組
請找出數組中任意一個重複的數字,但不能修改輸入的數組。測試
樣例:spa
給定長度爲8的數組 nums = [2, 3, 5, 4,3, 2, 6,7]code
那麼輸出重複的數字2或者3get
首先咱們得關注到,題目要求是:不修改數組,而後仍是 返回任意一個重複的數字
。因此解題思路相比而言變少了:博客
哈希表:跟上一題同樣,本題也能夠建立一個哈希表,若是原數組的每一個數字第一次出現,就把他放到哈希表中去,即原數組大小爲m的數字應該放到哈希表下標爲m的位置上。空間複雜度是 \(O(n)\) 。
二分法:那麼有沒有不用空間複雜度\(O(n)\) 的算法。假設沒有重複數,那麼 1~n 之間,每一個數都只能出現一次。而題目中,這個數組至少有一個數字重複,即出現的次數大於1。
利用二分的思想:把 1~n 的數字從中間數字m開始分爲兩部分,前一半爲 1~ m,後面一半爲 m+1 ~n,若是 1~m 中的數字在數組中出現的次數大於m,那麼這一半一定有重複的數字;不然,那麼另外一部分一定含有重複數字。接着咱們,繼續對含有重複數字的區間一分爲二,直到找到重複的數字。
def find_duplicated_num(nums): """hash_map""" hash_map = dict() for i, val in enumerate(nums): if val in hash_map: return val hash_map[val] = i return False
def reduce_inter(nums2, left, right): """ """ mid = (left + right) // 2 count = 0 length = len(nums2) for i in range(length): if (nums2[i] >= left) and (nums2[i] <= mid): count += 1 if count > mid - left + 1: return left, mid else: return mid+1, right def find_duplicated_num2(nums2): left, right = 1, len(nums2) - 1 while left != right: left, right = reduce_inter(nums2, left, right) return left
nums = [2, 3, 5, 4, 3, 2, 6, 7] # nums_n = [5, 4, 3, 2, 6, 7] print("思路一測試結果: ", find_duplicated_num(nums)) print("思路二測試結果: ", find_duplicated_num2(nums))
思路一測試結果: 3 思路二測試結果: 3
其實,這種算法不能保證找出全部重複的數字,好比不能找出[2, 3, 5, 4, 3, 2, 6, 7]重複數字2。