题目
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地修改输入数组 并在使用 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 。不需要考虑数组中超出新长度后面的元素。
考点(模式识别)
- 双指针法的应用:本题主要考查利用快慢指针的模式来解决在特定约束(原地修改、空间复杂度 O(1))下的数组元素去重问题。通过合理移动快慢指针,能够高效地遍历数组并完成去重操作,是对数组操作和指针运用的典型考查。
- 对排序数组特性的利用:题目给定的是排序数组,正是利用排序后相同元素相邻的这一特性,才能方便地通过比较相邻元素来判断是否重复,进而实现去重逻辑。
所有解法
- 双指针法(快慢指针):这是解决本题最常用也是较高效的方法,通过定义快慢两个指针,慢指针指向去重后数组的最后一个有效位置,快指针用于遍历整个数组,当快慢指针所指元素不同时,将快指针指向的元素复制到慢指针的下一个位置,以此实现去重。
解题步骤(双指针法)
- 初始化两个指针,
slow
指针初始化为 0,代表去重后数组的末尾位置;fast
指针从 1 开始,用于遍历整个数组(因为要和slow
指针所指元素比较,slow
初始位置为 0,所以fast
从 1 开始合适)。 - 开始遍历数组(通过移动
fast
指针),当nums[fast]
与nums[slow]
不相等时,意味着发现了一个新的不重复元素。- 将
nums[fast]
赋值给nums[slow + 1]
,相当于把新的不重复元素放到去重后数组的合适位置(也就是slow
指针的下一个位置)。 - 然后将
slow
指针向后移动一位(slow++
),更新去重后数组的末尾位置。
- 将
- 当
fast
指针遍历完整个数组后,slow + 1
的值就是去重后数组的长度,因为slow
指向的是去重后数组的最后一个有效元素的位置。
C 语言实现(双指针法)
// 函数功能:使用双指针法原地删除排序数组中的重复元素,并返回去重后数组的新长度
// 参数 nums:指向整型数组的指针,代表要处理的排序数组
// 参数 numsSize:整型,代表数组 nums 的元素个数
int removeDuplicates(int* nums, int numsSize) {
if (numsSize == 0) { // 如果数组为空,直接返回 0
return 0;
}
int slow = 0; // 慢指针,指向去重后数组的末尾位置,初始化为 0
for (int fast = 1; fast < numsSize; fast++) { // 快指针遍历数组,从 1 开始
if (nums[fast]!= nums[slow]) { // 当快慢指针所指元素不同时
slow++; // 先将慢指针向后移动一位
nums[slow] = nums[fast]; // 将快指针指向的元素复制到慢指针位置
}
}
return slow + 1; // 返回去重后数组的新长度(slow 指向最后一个有效元素,长度为 slow + 1)
}
上述代码中,首先判断了数组是否为空的特殊情况,如果为空则直接返回 0。然后利用 for
循环让快指针 fast
遍历数组,在循环内部,通过比较快慢指针所指元素是否相同来决定是否进行去重操作(即移动慢指针并复制元素),最后返回去重后数组的新长度。