題目說明
給定一個包含 n + 1 個整數的數組 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重複的整數。假設只有一個重複的整數,找出這個重複的數。
示例 1:
輸入: [1,3,4,2,2]
輸出: 2
示例 2:
輸入: [3,1,3,4,2]
輸出: 3
說明:
不能更改原數組(假設數組是隻讀的)。
只能使用額外的 O(1) 的空間。
時間複雜度小於 O(n2) 。
數組中只有一個重複的數字,但它可能不止重複出現一次。
解題思路一
- 先放一種前端比較好理解的。
- indexOf會返回數組中該元素出現的第一次的位置
- 我們利用這個特性,當indexOf的值跟目前的index不一致時,說明之前出現過一次。返回即可
代碼實現一
var findDuplicate = function(nums) {
let res = 0;
nums.map((item, key, arr) => {
if (arr.indexOf(item) !== key) {
res = item;
}
});
return res;
};
解題思路二(二分法)
- 首先看題意:數字範圍爲
1 ~ n
,那其實就是在1~n
的範圍內找到哪個元素在nums
中重複存在
。
- so,
1 ~ n
的序列。是有序
的,可以用二分找了,以1~n
爲基礎,以nums
爲條件判斷的元素。
- 那怎麼找呢。比如我們找到中間節點
mid
,判斷nums
數組中比mid小
的有多少個(prev)
,
- 按正常來講比如
mid爲3
,那麼從1到n <= 3
的數量應就是[1,2,3]
,一共是3
個啦。
- 所以如果重複的元素
比3小
的話,那麼3
的prev
就變成4以上
了,因爲[1,2,3]就變成了[1,1,2,3]
或者[1,2,2,3]
,等等,
- 所以我們就可以通過
prev
的大小來鎖定重複元素的範圍是在1 ~ mid
還是在mid+1 ~ n
;
- 接下來就很簡單了。就是一個二分法了。
代碼實現一
var findDuplicate = function(nums) {
let res = null;
function find(start, end, nums) {
if (end == start) {
return void ( res = end );
}
let mid = start + ((end - start) >> 1);
let prev = 0;
for (let i = 0; i < nums.length; i++) {
if (nums[i] <= mid) {
prev++;
}
}
if (prev > mid) {
find(start, mid, nums)
} else {
find(mid + 1, end, nums)
}
}
find(1, nums.length - 1, nums);
return res;
};