找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
它考察的是程序员的沟通能力,先问面试官要时间/空间需求!!!
只是时间优先就用字典,
还有空间要求,就用指针+原地排序数组,
如果面试官要求空间O(1)并且不能修改原数组,还得写成二分法!!!
先排序在查找(测试结果最优)
排序之后有重复的肯定是挨着的,然后前后两两比较,如果有重复的直接返回
var findRepeatNumber = function(nums) {
nums.sort();
for (let i = 1; i < nums.length; i++) {
if (nums[i] == nums[i - 1])
return nums[i];
}
return -1;
}
set()
var findRepeatNumber = function(nums) {
let s=new Set();
for(let num of nums){
let curLenth = s.size;
s.add(num);
if(s.size == curLenth){
return num;
}
};
return -1;
};
字典
哈希表map的结构是:map[number] = boolean,number 就是数组中的数字,boolean 代表数字是否出现过。
整体的流程是:遍历数组中的数字,检查是否出现过,第一次出现过就映射为true,下次出现就执行else语句,返回该数字。代码实现如下:
由于使用了哈希表,所以空间复杂度是 O(N)。需要遍历一次,时间复杂度是 O(N)。
var findRepeatNumber = function(nums) {
let map = {};
for (let num of nums) {
if (!map[num]) {
map[num] = true;
} else {
return num;
}
}
};
// 测试查看
var result = findRepeatNumber([2, 3, 1, 1, 3, 5, 3]);
console.log(result);
原地排序
原地哈希就是占位置,你是0你就占位置0, 是1243就占位置1243, 你要去占位置的时候发现位置倍别人占了, 说明有重复
所有数字都在 0 ~ n-1 的范围内。因此不需要额外开辟空间,每次遍历时,检查当前元素是否放在了正确位置上(例如元素 i 应该放在下标为 i 的位置上)。如果放在了正确位置上,那么继续循环。
- 下标为 num 的元素 === num,说明当前元素 num 是重复的,直接返回
- 下标为 num 的元素 !== num,交换当前元素和下标为 num 的元素,将当前元素放入到正确位置上
var findRepeatNumber = function(nums) {
const length = nums.length;
for (let i = 0; i < length; ++i) {
//检测下标为i的元素是否放在了位置i上
while ((num = nums[i]) !== i) {
if (num === nums[num]) {
return num;
}
[nums[i], nums[num]] = [nums[num], nums[i]];
}
}
};
尽管代码中有一个二重循环,但每个数字最多俩次就能找到自己的位置,因此总的时间复杂度为O(n),另外所有操作步骤待在原数组中进行,不需要额外分配内存,故空间复杂度为 O(1)。
二分法
找不到