Leetcode 删除排序数组中的重复项

本文最后更新于:2020年11月19日 上午

地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/

题目

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

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

示例 1:

给定数组 nums = [1,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。

你不需要考虑数组中超出新长度后面的元素。

说明:

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

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

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

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

我的解决方案:

题目给出了一个很重要的信息“排序”,千万不能遗漏,否则会耗费过多的时间用来遍历整个数组。

易错点:一般情况下会想到用两个 for 循环来做,外层循环遍历第一个到倒数第二个元素,内层循环遍历从外层循环当前遍历到的的下一个元素开始找出与当前元素值相同的元素并删去,大致逻辑如下:

for i in range(0, len(nums) - 1):
    for j in range(i + 1, len(nums)):
        if nums[i] == nums[j]:
            nums.pop(j)

看似逻辑没问题的,但是我们在内部删除了列表 nums[] 的元素之后,列表长度 len(nums) 就已经改变了,而 range() 函数的不会动态的根据 len(nums) 改变它的范围,最终就会导致删除元素后列表长度已经改变但是for语句不知道,超范围后仍然进入循环内部,当访问到 nums[j] 是已经超出列表索引范围。

正解:要解决上述问题,不难想到改用while循环,并且只需要一个循环即可,代码如下:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        i = 0  # 作为索引遍历列表元素
        while i < len(nums) - 1:  # 最多只遍历到倒数第二个元素
            if nums[i] == nums[i + 1]:  # 这就是问什么只遍历到倒数第二个元素的原因,因为始终要和下一个元素作比较
                nums.pop(i + 1)
                continue  # i保持不变,继续判断nums[i]和补位上来的nums[i + 1]是否相等
            i += 1
        return len(nums)

while语句中的 len(nums) 是动态更新的,这就解决了索引超出范围的问题;

continue 很重要,它解决了数组中有多个重复项的问题。