| No. | 题目名 | 中文简介 |
|---|---|---|
| 287 | Find the Duplicate Number | 寻找重复数 |
| 442 | Find All Duplicates in an Array | 数组中重复的所有数字 |
| 41 | First Missing Positive | 首个缺失的正数 |
| 268 | Missing Number | 缺失数字 |
| 448 | Find All Numbers Disappeared in an Array | 找到所有数组中消失的数字 |
这些题可以用相同的思路进行解题,题目的数据结构都是数字数组,个数有限,并且数字都被数组的长度限制。先遍历把数组中的数字放到对应的位置上,然后再遍历,如果一个位置上的数字不符合预期,则能找出结果。
var swap = function(nums, i, j) {
nums[i] ^= nums[j];
nums[j] ^= nums[i];
nums[i] ^= nums[j];
}
No.287
No.287我是用的快慢指针的方式解题的,这个题目跟寻找回路链表的交叉节点很像,只是数据结构换成了数组,可以完全根据回路链表的交叉节点的思路解题。 当然,这道题也可以使用数组归位法。
var findDuplicate = function(nums) {
var fast = nums[0];
var slow = nums[0];
var isFirst = true
while (fast !== slow || isFirst) {
isFirst = false;
if (fast && nums[fast]) {
fast = nums[fast];
fast = nums[fast];
} else {
return false;
}
slow = nums[slow];
}
slow = nums[0];
while (fast !== slow) {
fast = nums[fast];
slow = nums[slow];
}
return slow;
};
No.442
No.442由于同一个数字可能出现超过两次,如果使用数组归位法会输出多个相同的重复数字,这是不符合题意的,所以以下的代码不能通过。
// 重复频次多于两个的会重复输出。
var findDuplicates2 = function(nums) {
const res = [];
for (let i = 0; i < nums.length; i++) {
const pos = nums[i] - 1;
if (nums[pos] === nums[i]) {
if (i !== pos)
res.push(nums[i]);
} else {
swap(nums, pos, i);
i--;
}
}
return res;
}
由于题意表明 1 ≤ a[i] ≤ n (n = size of array),我们可以想象数字是地标指引,指引我们去另一个地标,当这个地标在之前已经出现过了,说明我们已经来过这个地方,也就是说该地标指引之前出现过了。当一个数字多次出现的时候,也就是该数字作为索引会发现多次同样的数字,此时我们将目标地数字置反表明来过即可。
// 访问记录法
var findDuplicates = function(nums) {
var res = [];
for (let i = 0; i < nums.length; i++) {
if (
// 发现刻字了,表明来过
nums[
Math.abs(nums[i]) - 1
] < 0
) {
res.push(
Math.abs(nums[i])
);
} else {
// 第一次来,刻字- -
nums[
Math.abs(nums[i]) - 1
] *= -1;
}
}
return res;
};
No.41
这道题使用归位法,将数字归位到对应的索引上,然后遍历归位后的数组,发现对应位置上的数字不符合,则该索引下本该存在的数字就是最小正数了
var firstMissingPositive = function(nums) {
for (let i = 0; i < nums.length; i++) {
const val = nums[i]
if (val >= 0 && val <= nums.length) {
const pos = val - 1;
if (val !== nums[pos]) {
swap(nums, i, pos);
i--;
}
}
}
for (let i = 0; i < nums.length; i++) {
if (nums[i] !== i + 1) {
return i + 1;
}
}
return nums.length + 1;
};
No.268
大家看了上面几个归位法,相信这道题也是很简单的能想到归位法(包括我),但是这道题有个很简单的思路(偷窥发现),就是利用同数字异或等于0这个特点。
题意是0 ≤ a[i] ≤ n (n = size of array),n + 1个数字,但是数组长度是n,所以有一个数字是不在数组里的,可以想象一下,如果把数组归位一下,其实数组里基本上是索引等于索引指向的内容,例如[0, 1, 2, 3],[0, 1, 2, 4],如果将索引和数字异或一下,可以根据归位后的数组,大多数情况下都等于0,只有缺失了数字才不为0
// 异或法
var missingNumber2 = function(nums) {
var res = nums.length;
for (let i = 0; i < nums.length; i ++) {
res ^= nums[i] ^ i;
}
return res;
}
No.448
归位法,在这类题目里最朴素实用
var findDisappearedNumbers = function(nums) {
var res = []
for (let i = 0; i < nums.length; i++) {
const pos = nums[i] - 1;
if (nums[pos] !== nums[i]) {
swap(nums, pos, i);
i--
}
}
for (let i = 0; i < nums.length; i++) {
if (nums[i] !== i + 1) {
res.push(i + 1);
}
}
return res;
};