难度:中等
题目描述
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
要求: 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
提示: 不需要考虑数组中超出新长度后面的元素。
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列
思路
采用双指针(fast & slow),fast 遍历数组,slow 最终是新数组的长度(把 slow 当做一个要填的坑)。
- fast 和 slow 从下标 2 开始;
- 当 fast 没有走完的时候一直循环(fast < nums.length);
- 当 nums[fast] == nums[slow-2],说明已经有三个连续的数字了,就需要将 fast 往后移动一个进行下一次比较。slow 不动,代表这个坑要被填上其他值使三个连续的数字变成两个;
- 当 nums[fast] != nums[slow-2] 时,nums[fast] = nums[slow], slow++,fast++(解释:要求每个元素最多出现两次且数组已经按照升序排列,因此只需要 中间隔一个 进行比较。赋值之后,slow 这个坑被填了就应该将 slow 和 fast往后移动一位去进行下一次比较。)
为什么用 fast 和 slow-2 进行比较?
因为 slow 所过之处必然是已经满足要求了,最多有 slow-1 和 slow-2 两个相同元素,而 fast 跑的快,它会扫过剩余数组去找要往坑里填的数字,所以说 fast 并不能改变数组,它只能遍历数组,与 slow-2 比较保证了最多有两个相同的元素。
实现
执行用时: 0 ms
内存消耗: 38.7 MB
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n <= 2) {
return n;
}
int s = 2;
int f = 2;
while(f < n){
if(nums[s-2]!=nums[f]){
nums[s] = nums[f];
++s;
}
++f;
}
return s;
}
}