给你一个有序数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

示例 1:
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度2,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 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 <= nums.length <= 3*104
-104 <= nums[i] <= 104
nums已按升序排列

思路

定义快慢指针,在快指针从前向后遍历的过程中,如果遇到新的值和当前慢指针的值不同,则慢指针向后递进一格并替换慢指针当前的值为快指针的值,这样就能跳过重复的元素,最后返回慢指针指向的下标+1(从0开始)就能得到正确的答案。

思路递推

以示例二中的 nums = [0,0,1,1,1,2,2,3,3,4]进行递推:

  • 定义慢指针i,快指针j,初始i = 0,j = 0。

  • 此时nums[i] = 0,nums[j] = 0,二者相等,慢指针i不动,快指针j继续向后递进。

  • i = 0,j = 1。

  • 此时nums[i] = 0,nums[j] = 0,二者相等,慢指针i不动,快指针j继续向后递进。

  • i = 0,j = 2。

  • 此时nums[i] = 0,nums[j] = 1,二者不相等,慢指针i向后递进,并替换当前nums[i]的值为nums[j],快指针j继续向后递进。

  • i = 1,j = 3。

  • 此时nums[i] = 1,nums[j] = 2,二者相等,慢指针i不动,快指针j继续向后递进。

  • i = 1,j = 4。

  • 此时nums[i] = 1,nums[j] = 2,二者相等,慢指针i不动,快指针j继续向后递进。

  • i = 1,j = 5。

  • 此时nums[i] = 1,nums[j] = 2,二者不相等,慢指针i向后递进,并替换当前nums[i]的值为nums[j],快指针j继续向后递进。

  • i = 2,j = 6。

  • 此时nums[i] = 2,nums[j] = 2,二者相等,慢指针i不动,快指针j继续向后递进。

  • i = 2,j = 7。

  • 此时nums[i] = 2,nums[j] = 3,二者不相等,慢指针i向后递进,并替换当前nums[i]的值为nums[j],快指针j继续向后递进。

  • i = 3,j = 8。

  • 此时nums[i] = 3,nums[j] = 3,二者相等,慢指针i不动,快指针j继续向后递进。

  • i = 3,j = 9。

  • 此时nums[i] = 3,nums[j] = 4,二者不相等,慢指针i向后递进,并替换当前nums[i]的值为nums[j],快指针j继续向后递进。

  • 此时快指针到达末尾,退出循环,答案为慢指针i+1,即为5。

代码实现

    public static int removeDuplicates(int[] nums) {
        int length = nums.length;
        //定义快慢指针,只有当快指针的值和慢指针不相等时,慢指针前进一格并替换当前快指针的值
        int i = 0,j = 0;
        while (j < length){
            if (nums[i] != nums[j]){
                i++;
                nums[i] = nums[j];
            }
            j++;
        }
        return i+1;
    }

    public static void test(){
        System.out.println(removeDuplicates(new int[]{0,0,1,1,1,2,2,3,3,4}));
    }