题目 26. 删除有序数组中的重复项
给你一个 非严格递增排列 的数组
nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回nums
中唯一元素的个数。
考虑 nums
的唯一元素的数量为 k
,你需要做以下事情确保你的题解可以被通过:
- 更改数组
nums
,使nums
的前k
个元素包含唯一元素,并按照它们最初在nums
中出现的顺序排列。nums
的其余元素与nums
的大小不重要。 - 返回
k
。
示例
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
根据题意可知,函数需要满足以下两个条件:
- 返回数组中唯一元素的数量k
- 原地修改数组nums,保证数组前k项为唯一元素的集合,且不改变元素的相对顺序
题解1:
一开始我没有理解到数组是 非严格递增排列 这个特性,所以采用了先对数组去重,再将去重后留下的元素挪到数组左侧的做法。
- 首先遍历数组,借助Map去重,将重复元素标记为 _
- 双指针遍历去重后的nums: i 寻找可填入元素的位置,即当前元素是 _;j寻找非重复元素即数字
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let map = new Map()
for(let i =0; i< nums.length; i++) {
// map中有这个元素,则认为是重复出现 标记为 _
if(map.has(nums[i])) {
nums[i] = '_'
} else {
// map中没有则认为是唯一元素,存入map中
map.set(nums[i])
}
}
let i = 0
let j = 1
while(i < nums.length && j < nums.length) {
// 当 i 位置的元素为 _, j 位置的元素为数字时,将 nums[j]的值赋值给nums[i]
if(nums[i] == '_' && nums[j] != '_') {
nums[i] = nums[j]
nums[j] = '_'
i++
j++
}
// 当前位置不是_,则不是可替换位置,i++
if(nums[i] != '_') {
i++
}
// nums[j] == '_'当前位置不是有效数值 或 j<=i时, j++
if(nums[j] == '_' || j <= i) {
j++
}
}
// map.size就是k
return map.size
};
题解2
数组nums为非严格递增排列,即数组是有序的,那么重复的元素一定是相邻的;那么就可以不进行去重操作,只将数组中不重复的元素移到数组的左侧即可
依然采用双指针的做法:
- 设置指针 i, j。i表示,i以及之前的元素都是不重复的;j指针始终比i指针快,来寻找下一个不重复元素;
- 比较i 和 j 位置上的元素是否相等: 如果nums[i] == nums[j],表示元素重复,j++继续寻找不重复的元素;如果nums[i] != nums[j]则i位置更新向后移动i++且nums[i]保存nums[j], j指针更新
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
遍历过程如下:
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let i = 0
let j = 1
while(i < nums.length && j< nums.length) {
if(nums[i] == nums[j]) {
j++
} else {
i++
nums[i] = nums[j]
j++
}
}
return i + 1
};
代码如下:
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let i = 0
let j = 1
while(i < nums.length && j< nums.length) {
if(nums[i] == nums[j]) {
j++
} else {
i++
nums[i] = nums[j]
j++
}
}
return i + 1
};
代码优化: 分析上述代码可以看到,不论if条件是否满足j指针都需要更新,所以可以修改一下判断条件,优化一下j指针的更新
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let i = 0
let j = 1
while(i < nums.length && j< nums.length) {
if(nums[i] != nums[j]) {
i++
nums[i] = nums[j]
}
j++
}
return i + 1
};