解题过程
:::info
题目链接
集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums 代表了集合 S 发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
:::
/**
* @link https://leetcode.cn/problems/set-mismatch/
* @title 645. 错误的集合
* @description 集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
* 给定一个数组 nums 代表了集合 S 发生错误后的结果。
* 请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回
* @param {number[]} nums
* @return {number[]}
*/
// 解法一:
// var findErrorNums = function (nums) {
// nums.sort((a, b) => a - b)
// console.log(nums)
// for (let i = 0; i < nums.length; i++) {
// if (nums[i] === nums[i + 1]) {
// // const minNums = nums.find(i => i !== nums[i])
// if (nums[i] === 1) {
// return [nums[i], nums[i + 1]]
// } else if (nums[i] === 2) {
// return [nums[i], 1]
// }
// // return [nums[i], Math.max(1, nums[i] - 1, nums[i] + 1)]
// }
// }
// }
// 解法二:穷举所有遇到的情况判断处理,结果失败
// 不考虑排序,直接遍历数组nums, 判断当前索引项跟下一个索引项是否相同
// 相同则记录当前值和下一个被重复的值 + 1 就是丢失的值❌,因为重复的值不一定就是相邻的数字,比如[ 2, 3, 4, 4, 5 , 7 ],重复的数字是4,但丢失的数字缺不是5
// 暂不考虑数组排序问题,默认有小到大排好序
// var findErrorNums = function (nums) {
// const res = []
// for (let i = 0; i < nums.length; i++) {
// if (nums[i] === nums[i + 1]) {
// res.push(nums[i], nums[i] + 1)
// }
// }
// return res
// }
// 考虑重复的数字不相邻问题:判断当前项与下一项相同的同时,加上判断下下一项是否等于当前项+1的值(不存在当前值则判断前一项值是否相差1)
// 如果相同,则重复丢失的数据不是相邻项;不相同则是
// 不存在,判断当前值和前一项值是否相差1,如果是则是第一项减一的值为丢失数据的值,如果不是,这是当前项减一为丢失数据的值
// 穷举所有情况的方式,失败❌,太多情况需要考虑到了,而且数据量大的时候不好处理
var findErrorNums = function (nums) {
const res = []
nums.sort((a, b) => a - b)
console.log(nums)
for (let i = 0; i < nums.length; i++) {
if (nums[i] === nums[i + 1]) {
if (i + 2 < nums.length) {
if (nums[i] + 1 === nums[i + 2]) {
if (i !== 0) {
if (nums[i] - 1 === nums[i - 1]) {
if (nums[i - 1] === 1) {
res.push(nums[i], nums[nums.length - 1] + 1)
} else {
res.push(nums[i], nums[i - 1] - 1)
}
} else {
res.push(nums[i], nums[i] - 1)
}
} else {
res.push(nums[i], nums[i] - 1)
}
} else {
res.push(nums[i], nums[i] + 1)
}
} else {
if (i === 0 || nums[i] - 1 === nums[i - 1]) {
if (nums[0] >= 2) {
res.push(nums[i], nums[0] - 1)
} else {
res.push(nums[i], nums[i] + 1)
}
} else {
res.push(nums[i], nums[i] - 1)
}
}
}
}
return res
}
// 解法三:map数字标记法(map的集合元素唯一性)注意题目信息:1到n的整数集合,说明数组nums最大值是n,最小值是1,跟数组索引对应
// 第一步:遍历数组所有元素值,对应key-value为数组索引值和是否重复的索引值,重复的索引值value更改为2,否则默认为1
// 第二步:遍历数组,判断当前索引对应map的key值是不是等于2,说明是重复的数字位置,判断当前索引是否为空,为空则为丢失的位置数字
var findErrorNums = function(nums) {
const map = new Map()
let res = []
for (const value of nums) {
if (map.has(value)) {
map.set(value, map.get(value) + 1)
} else {
map.set(value, 1)
}
}
for (let i = 1; i <= nums.length; i++) {
if (map.get(i) === 2) res[0] = i
if (!map.get(i)) res[1] = i
}
return res
}
// const case2 = findErrorNums(nums = [1, 2, 2, 4]) // [2,3]
// const case2 = findErrorNums([2, 2]) // [2,1]
// const case2 = findErrorNums([1, 1]) // [1, 2]
// const case3 = findErrorNums([5, 5, 6]) // [5, 4]
// const case3 = findErrorNums([2, 2, 3]) // [2, 1]
// const case3 = findErrorNums([3, 2, 2]) // [2, 1]
// const case3 = findErrorNums([1, 3, 3]) // [3, 2]
// const case3 = findErrorNums([1, 2, 3, 3, 6, 5]) // [3, 4]
// const case3 = findErrorNums([ 2, 3, 3, 4, 5, 6 ]) // [3, 1]
// const case3 = findErrorNums([ 2, 3, 4, 4, 5 , 7 ]) // [4, 1]
// const case3 = findErrorNums([ 1, 3, 3]) // [3, 2]
// const case3 = findErrorNums([8, 7, 3, 5, 3, 6, 1, 4]) // [3, 2]
// const case3 = findErrorNums([3,2,3,4,6,5]) // [3, 1]
const case3 = findErrorNums([5,3,6,1,5,4,7,8]) // [5, 2]
console.log(case3)
解题感受
一开始只会用传统穷举的方法解题,测试用例通过20题报错后发现这个解题思路不太正确就换了另一种解题思路,不过想了10分钟没有思路看别人的解法才想到的,看懂后加上自己的理解注释做了出来(详细看打卡链接注释内容)
真的要多注意审题,看完题目做了一会还是没有思路的时候,做好的方式再坚持一下,看看从题干中分析解题思路和寻找破解口