问题描述
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
- 不能更改原数组(假设数组是只读的)。
- 时间复杂度小于
O(n*n) 。
- 数组中只有一个重复的数字,但它可能不止重复出现一次。
解法
不考虑空间复杂度:O(n),Array 或者 Map 缓存访问过的值
暴力方法(时间复杂度不满足)
function getRepeat(arr) {
const len = arr.length
let result
for (let i = 0; i < len-1; i ++) {
for (let j = i+1; j < len; j ++) {
if (arr[i] === arr[j]) {
result = arr[i]
}
}
if (result !== undefined) {
break
}
}
return result
}
Map 缓存(可用数组)
function getRepeat(arr) {
const ret = {}, len = arr.length
let i
for (i = 0; i < len; i++) {
if (ret[arr[i]]) {
break
}
ret[arr[i]] = 1
}
return i === len ? undefined : arr[i]
}
其他想法
如果确认只有一个元素重复,可以结合鸽笼原理和 N 个数求和相减即可。
面试官想要的解法
二分法猜元素,遍历查找,比如刚开始猜测试 M = Math.floor(N / 2),那么遍历小于 M 的元素个数,和大于 M 的元素个数,根据结果推断是在那边,然后继续,直到找到元素。
function getRepeat(arr) {
const len = arr.length
// n+1 => [1, n]
let min = 1, max = len - 1
let guess
do {
guess = Math.floor((min + max) / 2)
let smallCount = 0, bigCount = 0
for (let i = 0; i < len; i++) {
if (arr[i] > guess) {
bigCount ++
} else if (arr[i] < guess) {
smallCount ++
}
}
if (smallCount > (guess - min)) {
max = guess - 1
} else if (bigCount > (max - guess)) {
min = guess + 1
} else {
break
}
} while (min <= max)
return guess
}
问题描述
给定一个包含
n + 1个整数的数组nums,其数字都在1到n之间(包括1和n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。示例 1:
输入:
[1,3,4,2,2]输出:
2示例 2:
输入:
[3,1,3,4,2]输出:
3说明:
O(n*n)。解法
不考虑空间复杂度:
O(n),Array或者Map缓存访问过的值暴力方法(时间复杂度不满足)
Map缓存(可用数组)其他想法
如果确认只有一个元素重复,可以结合鸽笼原理和
N个数求和相减即可。面试官想要的解法
二分法猜元素,遍历查找,比如刚开始猜测试
M = Math.floor(N / 2),那么遍历小于M的元素个数,和大于M的元素个数,根据结果推断是在那边,然后继续,直到找到元素。