题目描述:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
示例一:
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例二:
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
解题思路:
使用了两种方式解答改题,发现在函数中使用splice函数会大大增加整个程序的运行时间。
方法一:单指针暴力解法
用一个变量i对整个数组做出一个遍历,若nums[i]
与nums[i+1]
相等,则用splice(index,num)
函数将数组中对应下标的元素删除,若两者不相等,则指针前进,这样的方式能保证在遍历完成的时候数组整个也发生了变化,没有多余的元素,但是频繁使用splice函数也使得整个程序的运行时间和占用的内存很长,而且题目中也只需要返回数组长度,那么就无需每次都对整个数组做出处理。
源码如下
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let i = 1;
if(nums.length >= 2){
//数组长度不为零且不只有一个元素
while(i<nums.length){
if(nums[i] == nums[i-1]){
//将重复元素删除
nums.splice(i,1);
}else{
i++;
}
}
}
return nums.length;
};
方法二:双指针赋值解法
使用两个指针,一个快指针遍历整个数组,一个慢指针用来更新重复的数值
若nums[i] == nums[j]
,则快指针j向后移寻找不同的数值,找到不同的数值后将nums[j]
赋值给nums[i+1]
若nums[i] != nums[j]
,则说明慢指针指向的位置不需要做重复数修改,将慢指针推进i++
当快指针j将整个数组遍历完,也就结束了重复项的删除,nums[i]
所在的地方就是删除重复项后的数组的最后一项,那么新数组的长度就是i+1
,故返回i+1
。
源码如下:
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let i = 0;//慢指针
let j = 1;//快指针
if(nums.length >= 2){
//数组不为空且数组不只有一个元素
while(j<nums.length){
if(nums[i] == nums[j]){
j++;
}else{
nums[i+1] = nums[j];
i++;
}
if(i == j){
j++;
}
// console.log(nums);
}
}
return i+1;
};
运行结果对比: