leetcode 面试经典 150 题(3/150) 26.删除有序数组中的重复项

135 阅读2分钟

题目描述

给定一个非严格递增排列的整数数组 nums,要求原地删除所有重复元素,使每个元素仅出现一次,并保持元素的相对顺序。返回新数组的长度。

算法思路

快慢指针法:利用双指针技巧,快指针遍历数组,慢指针标记唯一元素的位置。

具体步骤

  1. 处理空数组:若数组为空,直接返回0。
  2. 初始化指针
    • p1(慢指针):初始指向数组起始位置,标记当前唯一元素的末尾。
    • p2(快指针):从第二个元素开始遍历,寻找与当前唯一元素不同的值。
  3. 遍历数组
    • nums[p2] != nums[p1] 时,说明找到新的唯一元素,将 p1 后移一位,并将 p2 的值赋给 p1 的位置。
    • 重复上述过程直到 p2 遍历完整个数组。
  4. 返回结果:最终唯一元素的数量为 p1 + 1

图解示例

nums = [0,0,1,1,1,2,2,3,3,4] 为例:

步骤p1 位置p2 位置操作nums 状态
初始01-[0,0,1,1,1,2,2,3,3,4]
10→12发现1,赋值到p1=1[0,1,1,1,1,2,2,3,3,4]
21→25发现2,赋值到p1=2[0,1,2,1,1,2,2,3,3,4]
32→37发现3,赋值到p1=3[0,1,2,3,1,2,2,3,3,4]
43→49发现4,赋值到p1=4[0,1,2,3,4,2,2,3,3,4]
终止--返回 p1+1 =5前5个元素为 [0,1,2,3,4]

复杂度分析

  • 时间复杂度:O(n),每个元素仅被遍历一次。
  • 空间复杂度:O(1),原地修改数组,未使用额外空间。

代码实现

func removeDuplicates(nums []int) int {
    if len(nums) == 0 {
        return 0
    }
    p1 := 0
    for p2 := 1; p2 < len(nums); p2++ {
        if nums[p2] != nums[p1] {
            p1++
            nums[p1] = nums[p2]
        }
    }
    return p1 + 1
}

关键点总结

  1. 有序数组特性:重复元素必然相邻,快指针跳过重复项。
  2. 原地修改:通过慢指针记录有效位置,直接覆盖无需额外空间。
  3. 边界处理:空数组直接返回,非空数组至少有一个唯一元素。