Jex

01-【26】删除有序数组中的重复项

2021/07/23 难度:简单
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array

题目

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

解答

第一天刷题,其实我对这道题是没有思路的,在想了十分钟之后果断去看了题解,然后自己想了一遍,理解双指针是什么。

读题(理解题目意思)

首先注意数组是有序的,那么重复的元素一定会相邻。(读题的时候我 get 不到这个意思)
要求删除重复元素,实际上就是将不重复的元素移到数组的左侧。(我只想到了删除元素)

思考

考虑用 2 个指针,一个在前记作 p,一个在后记作 q。
算法流程如下:

  1. 判断指针 p 和指针 q 所指向的元素是否相等;
  2. 如果相等,指针 q 后移一位;如果不相等,将指针 q 指向的元素复制到指针 p+1 位置上,指针 p 后移一位,指针 q 也后移一位;
  3. 重复上述过程,直到指针 q 等于数组长度。
  4. 返回 p + 1,即为结果数组的长度。

具体的理解就是:
【0,0,1,1,1,2,2,3,3,4】

我有一堆已排序好的号码牌,我需要把不重复的数字按序排在前面。

  1. 如果第一个和第二个是相同的数字,那么第二个位置肯定要被替换掉的。

  2. 那么对比第一个和第三个数字,如果数字不相同,把第三个数字替换到第二个位置,就变成了:

【0,1,1,1,1,2,2,3,3,4】
然后,这时候第一个位置和第二个位置肯定是不重复的了,第二个位置和第三个位置肯定是重复的。所以开始对比第二个和第四个数字,如果相同,那么第四个位置也是要被后面的替换的。

重复以上过程:(红色代表初始比对值)
初始值:【0,0,1,1,1,2,2,3,3,4】
第一次:【0,1,1,1,1,2,2,3,3,4】
第二次:【0,1,2,1,1,2,2,3,3,4】
第三次:【0,1,2,3,1,2,2,3,3,4】
第四次:【0,1,2,3,4,2,2,3,3,4】

代码

function removeDuplicates(nums: number[]): number {
    let p = 0;
    for(let q = 1; q < nums.length; q++) {
      if(nums[p] !== nums[q]) {
        nums[++p] = nums[q];
      }
    }
    nums.length = p + 1;
    return nums.length;
};

复杂度分析

时间复杂度:O(n),其中 n 是数组的长度。快指针和慢指针最多各移动 n 次。
空间复杂度:O(1)。只需要使用常数的额外空间。