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

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

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

  1. int[] nums = [...]; // Input array
  2. int[] expectedNums = [...]; // The expected answer with correct length
  3. int k = removeDuplicates(nums); // Calls your implementation
  4. assert k == expectedNums.length;
  5. for (int i = 0; i < k; i++) {
  6. assert nums[i] == expectedNums[i];
  7. }

示例 1:

  1. Input: nums = [1,1,2]
  2. Output: 2, nums = [1,2,_]
  3. Explanation: Your function should return k = 2, with the first two elements of nums being 1 and 2 respectively.
  4. It does not matter what you leave beyond the returned k (hence they are underscores).

示例 2:

  1. Input: nums = [0,0,1,1,1,2,2,3,3,4]
  2. Output: 5, nums = [0,1,2,3,4,_,_,_,_,_]
  3. Explanation: Your function should return k = 5, with the first five elements of nums being 0, 1, 2, 3, and 4 respectively.
  4. It does not matter what you leave beyond the returned k (hence they are underscores).

提示:

  • 0 ≤ nums.length ≤ 3 × 10;
  • -100 ≤ nums[i] ≤ 100;
  • nums已按升序排列

思路

使用双指针法。其中i是慢指针,j是快指针。遍历数组,做出如下判断:

  • nums[i] == nums[j]时,递增j以跳过重复项;
  • nums[i] != nums[j]时,把nums[j]的值复制到nums[i+1],再递增i;
  • 重复上述过程,直到j到达数组末尾位置。

考虑一种特殊场景,数组nums中没有重复元素。按照上面的方法,每次比较nums[i]都不等于nums[j],则将j指向的元素原地复制一遍,这个操作其实是不必要的,因此应该添加一个判断:当重复元素的个数大于1时才进行复制。

代码

Rust:

  1. // 0ms, 2.2MB
  2. impl Solution {
  3. pub fn remove_duplicates(nums: &mut Vec<i32>) -> i32 {
  4. if nums.len() == 0 {
  5. return 0;
  6. }
  7. let mut slow_index = 0;
  8. for fast_index in 1 .. nums.len() {
  9. if nums[slow_index] != nums[fast_index] {
  10. if fast_index - slow_index > 1 {
  11. nums[slow_index+1] = nums[fast_index];
  12. }
  13. slow_index += 1;
  14. }
  15. }
  16. (slow_index + 1) as i32
  17. }
  18. }