🚅【leetcode】442. 数组中重复的数据
🚀题目
给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[2,3]
示例 2:
输入:nums = [1,1,2]
输出:[1]
示例 3:
输入:nums = [1]
输出:[]
提示:
n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
nums 中的每个元素出现 一次 或 两次
💥leetcode代码模板
/**
* @param {number[]} nums
* @return {number[]}
*/
var findDuplicates = function(nums) {
};
🚀思路
leetcode官方还是太好了,把关键词都加粗了,生怕我这种初级选手没有思路。
注意题目中加粗的文字:一次或两次
数组的长度为n,数字的范围为[1,n],数字又只能出现一次或两次,那么思路就有了:
数组本身具有的东西就是索引,除非你这个数字出现了两次,否则索引又刚好可以和数字一一对应。
所以我们可以找出那些不是一一对应的数字,添加到结果数组就好了。
现在问题来了,怎么找而又指利用常量而外空间呢?
我们得标记出现过的数字,当再次遇到它时就说明它出现了两次!这里介绍两种标记方式:
1️⃣交换元素
- 当遇到一个
nums[i]
发现nums[i] - 1 !== i
,那就把它挪到它与索引对应的位置,例如1应该对应索引0,4对应索引3。 - 当再次遇到该数字,检查一下它对应索引位置处的值是否等于它,是的话说明重复,添加到结果中。
- 由于我们交换了元素,所以有可能导致重复判断一个数字,所以要对结果进行去重。
2️⃣不交换元素
-注意到题目中数字都是正数,那么我们可以把出现过的数字对应的索引处的值取反变为负数,从而进行标记。
- 遍历数组,如果发现当前数字的绝对值对应的索引处的值小于0,就把该值加入结果,否则就标记对应索引位置的值。
- 由于我们没有交换元素,每个元素只会遍历一次,因此不用去重。
💻代码
var findDuplicates = function(nums) {
let ans = new Set()
function wrap(i , j){
let temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
}
for(let i = 0 ; i < nums.length ; i++){
let j = nums[i] - 1
if(i !== j){
if(nums[i] === nums[j]){
ans.add(nums[i])
}else{
wrap(i , j)
i-- // 交换过来的数字还没判断过
}
}
}
return Array.from(ans)
};
var findDuplicates = function(nums) {
let ans = []
let len = nums.length
for(let i = 0 ; i < nums.length ; i++){
let j = Math.abs(nums[i]) - 1
if(nums[j] < 0) ans.push(Math.abs(nums[i]))
else nums[j] *= -1
}
return ans
};
🍪总结
这道题主要是学习这种原地标记的思想。
✨ 我 是 c o n e r , 请 别 关 注 我 的 专 栏 , 本 系 列 文 章 为 个 人 刷 题 记 录 ( 偷 偷 自 己 卷 🤤 ) : \textcolor{green}{我是coner,请别关注我的专栏,本系列文章为个人刷题记录(偷偷自己卷🤤):} 我是coner,请别关注我的专栏,本系列文章为个人刷题记录(偷偷自己卷🤤):leetcode题解js
✨ 每 天 更 新 3 道 l e e t c o d e 题 目 的 j s 题 解 🚀 🚀 🚀 \textcolor{green}{每天更新3道leetcode题目的js题解🚀🚀🚀} 每天更新3道leetcode题目的js题解🚀🚀🚀