80. 删除有序数组中的重复项 II(数组)

260 阅读2分钟

难度:中等

题目描述

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。

要求: 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

提示: 不需要考虑数组中超出新长度后面的元素。

1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列

思路

采用双指针(fast & slow),fast 遍历数组,slow 最终是新数组的长度(把 slow 当做一个要填的坑)。

  1. fast 和 slow 从下标 2 开始;
  2. 当 fast 没有走完的时候一直循环(fast < nums.length);
  3. 当 nums[fast] == nums[slow-2],说明已经有三个连续的数字了,就需要将 fast 往后移动一个进行下一次比较。slow 不动,代表这个坑要被填上其他值使三个连续的数字变成两个;
  4. 当 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;
    }
}