给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
题目来源:力扣(LeetCode)
输入: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 。不需要考虑数组中超出新长度后面的元素。
解题思想:利用数组有序的特点,可以通过双指针的方法删除重复元素。如果数组的长度为0,则数组不包含任何元素,因此返回0。当数组的长度大于0 时,数组中至少包含一个元素,在删除重复元素之后也至少剩下一个元素,因此数组第一个元素保持原状即可,从下标 1 开始删除重复元素。
定义两个指针 fast 和 slow 分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个不同元素要填入的下标位置,初始时两个指针都指向下标1。设数组的长度为n。将快指针fast 依次遍历从 1 到 n−1 的每个位置,对于每个位置,如果[fast]和[fast-1]元素不相等说明[fast] 和之前的元素都不同,因此将 [fast] 位置的值复制到[slow],然后将 slow 的值加 1,即指向下一个位置。
var removeDuplicates = function(nums) {
const n = nums.length;
//如果数组长度为0则直接返回
if (n === 0) {
return 0;
}
//设置fast、slow两个指针,
let fast = 1, slow = 1; //保留至少一个元素,故初始值设为1
//当fast小于数组长度时候遍历数组
while (fast < n) {
//当fast指向的元素不与前一元素相同时候,将其赋值给slow指针指向的重复元素位置
if (nums[fast] !== nums[fast - 1]) {
nums[slow] = nums[fast];
//赋值完后,slow指针往前走
++slow;
}
//当前元素出现多个重复的时候往前遍历
++fast;
}
//返回的slow指标就是去重后数组的长度
return slow;
};
拓展:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
题目来源:[力扣(LeetCode)]
可以看到此题是上面题目的拓展,思路都是一样的,只是判断条件稍作修改就可以解决此类拓展的问题
var removeDuplicates = function(nums) {
const n = nums.length;
//有序的数组决定了数组长度少于2时候直接返回
if (n <= 2) {
return n;
}
//因为保留两个重复的元素,初始值下标直接设为2
let slow = 2, fast = 2;
while (fast < n) {
/*因为保留两个重复的元素,所以判断slow指向元素的上上个元素是否和当前fast元素相同来决定
是否保留fast指向的元素,当slow-2指向元素与当前fast指向元素相同则数组slow前已有不重复的两个元素
此时fast往下寻找不重复的元素*/
if (nums[slow - 2] != nums[fast]) {
//如果nums[slow-2]==nums[fast],则有nums[slow-2]==nums[slow-1]==nums[slow]==nums[fast]
nums[slow] = nums[fast];
++slow;
}
++fast;
}
//遍历完成后slow即是去重后数组长度
return slow;
};