給定一個長度爲 n+1 的數組nums,數組中全部的數均在 1∼n 的範圍內,其中 n≥1。java
請找出數組中任意一個重複的數,但不能修改輸入的數組。c++
樣例
給定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。算法
返回 2 或 3。
思考題:若是隻能使用 O(1) 的額外空間,該怎麼作呢?數組
跟上一題同樣,但不能像上題同樣使用swap,雖然一樣能夠用HashMap解決,但仍是直接考慮"思考題"的作法吧。
能夠想象是要將n+1個數放到n個槽位裏,那一定有一個數要放到同一個槽位裏,這其實就是抽屜原理。
具體作法能夠用分治思想,將[1,n]區間分爲[1, n/2]和[n/2+1, n]兩個區間,而後在數組nums中計算出落在[1,n/2]區間的數字個數,是否比區間的數字個數還要多,多則說明區間的槽位放不下數組落在該區間的全部數,數組中一定有數放到同個槽位(即有重複),在該區間繼續二分查找。若是在[1,n/2]的區間能夠放下數組中落在該區間的全部數,則結果一定在另外一邊的區間裏,在[n/2+1, n]區間繼續二分查找。最後l == r,nums[l]或者nums[r]便是結果。code
class Solution { public int duplicateInArray(int[] nums) { if(nums == null || nums.length == 0) return -1; int l = 1, r = nums.length - 1; //注意邊界條件,本題區間是[1,n] //二分 while(l < r) { int mid = (l + r) >> 1; //除以2 分紅兩個區間[l, mid] [mid + 1, r] //計算nums中落在[l,mid]區間的個數c int c = 0; for(int i=0;i<nums.length;i++) { if(nums[i] >= l && nums[i] <= mid) c++; } if(c > (mid - l + 1)) { //區間[l,mid]的長度是(mid - l + 1) //[l,mid]區間放不下數組落在該區間的全部數,縮小區間 r = mid; } else l = mid + 1; } return r; } }