题目描述
给定一个非严格递增排列的整数数组 nums,要求原地删除所有重复元素,使每个元素仅出现一次,并保持元素的相对顺序。返回新数组的长度。
算法思路
快慢指针法:利用双指针技巧,快指针遍历数组,慢指针标记唯一元素的位置。
具体步骤
- 处理空数组:若数组为空,直接返回0。
- 初始化指针:
p1(慢指针):初始指向数组起始位置,标记当前唯一元素的末尾。p2(快指针):从第二个元素开始遍历,寻找与当前唯一元素不同的值。
- 遍历数组:
- 当
nums[p2] != nums[p1]时,说明找到新的唯一元素,将p1后移一位,并将p2的值赋给p1的位置。 - 重复上述过程直到
p2遍历完整个数组。
- 当
- 返回结果:最终唯一元素的数量为
p1 + 1。
图解示例
以 nums = [0,0,1,1,1,2,2,3,3,4] 为例:
| 步骤 | p1 位置 | p2 位置 | 操作 | nums 状态 |
|---|---|---|---|---|
| 初始 | 0 | 1 | - | [0,0,1,1,1,2,2,3,3,4] |
| 1 | 0→1 | 2 | 发现1,赋值到p1=1 | [0,1,1,1,1,2,2,3,3,4] |
| 2 | 1→2 | 5 | 发现2,赋值到p1=2 | [0,1,2,1,1,2,2,3,3,4] |
| 3 | 2→3 | 7 | 发现3,赋值到p1=3 | [0,1,2,3,1,2,2,3,3,4] |
| 4 | 3→4 | 9 | 发现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
}
关键点总结
- 有序数组特性:重复元素必然相邻,快指针跳过重复项。
- 原地修改:通过慢指针记录有效位置,直接覆盖无需额外空间。
- 边界处理:空数组直接返回,非空数组至少有一个唯一元素。