Leetcode HOT 100 —— 448.找到所有数组中消失的数字
数组
题目描述
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
进阶: 你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
解题思路
通过 索引 找到缺失的数字。
解题代码
第一种解法 使用另一个数组存放出现过的值
var findDisappearedNumbers = function(nums) {
let arr = [], res = []
for(let i = 0; i < nums.length; i++) {
arr[nums[i]-1] = nums[i]
}
for(let i = 0; i < arr.length; i++) {
if(arr[i] == null) {
res.push(i+1)
}
}
return res
};
时间复杂度虽然可以满足,但是不符合进阶要求。空间复杂度是 O(m)
第二种解法 减1取反
对每个值减 1后得到的数对应索引位置的值取相反数,最后判断值为非负数的索引加 1为缺失的数字
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| 值 | 4 | 3 | 2 | 7 | 8 | 2 | 3 | 1 |
| 值 | -4 | -3 | -2 | -7 | 8 | 2 | -3 | -1 |
const len = nums.length
for(let i = 0; i < len; i++) {
let x = nums[i] -1
// 如果值小于0,就取反后再减一。因为会出现重复的数字,所以做这步操作
if(nums[i] < 0) x = -nums[i] - 1
// 如果值小于0,跳过。避免出现多次取反的情况,只取一次反
if(nums[x] < 0) continue
nums[x] = -nums[x]
}
const result = []
for(let i = 0; i< len; i++) {
// 筛选,找到没有被取反的值的索引
if(nums[i] > 0) {
result.push(i+1)
}
}
return result
第三种解法 减1取余
上一种思路是对值取反,这次我们为他加数组的长度后取余获取原来的值
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| 值 | 4 | 3 | 2 | 7 | 8 | 2 | 3 | 1 |
| 值 + len | 12 | 11 | 10 | 15 | 8 | 2 | 11 | 9 |
| -1取余 | 3 | 2 | 1 | 6 | 7 | 1 | 2 | 0 |
减1取余后没有 4 和 5 的索引,符合预期,代码实现一下。
var findDisappearedNumbers = function(nums) {
const len = nums.length
for(let i = 0; i < len; i++) {
// 减1后取len的余数,恢复原来的值
let x = (nums[i] - 1) % len
nums[x] += len
}
const result = []
for(let i = 0; i< len; i++) {
// 只有未改变的值小于 len,找到后对索引加1
if(nums[i] <= len) {
result.push(i+1)
}
}
return result
};
类似题目:剑指 Offer 53- II. 0~n-1中缺失的数字
题目描述:
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
这题虽然和上题很相似,但还是有坑,做完上面的题后,再看这题,你会很直接的想复杂了。这题必上题要简单的多,因为他只找一个不在数组中的数字。我直接写解法
第一种解法 一次循环遍历
思路非常简单,每次迭代判断,索引和对应的值是否相等,不相等就返回这个索引并结束循环。如果循环到最后都不符合判断条件,说明它缺失数组length的数字。那么就返回 num.length
var missingNumber = function(nums) {
for(let i = 0; i < nums.length; i++) {
if(nums[i] !== i) return i
}
return nums.length
};
第二种解法 二分查找
var missingNumber = function(nums) {
let left =0, right = nums.length - 1
while(left <= right){
let mid = Math.floor((left + right) / 2)
if(nums[mid] == mid){
left = mid +1
}else{
right = mid -1
}
}
return left
};