题目快速通道

删除有序数组中的重复项删除有序数组中的重复项II

1、删除有序数组中的重复项

题目的大体意思就是对有序数组去重,并且需要原地处理,就是返回原数组,指定结束节点即可。

理解 + 解题

这条题目首先给出有序数组,如果不是有序数组的话,去重则需要排序或者哈希,既然原地,基本方法就是双指针,把唯一的元素逐个往前挪即可。
可以先设置两个指针 left 和 right,left维护唯一的有序数组,right作为遍历的指针。
由于是去重且保留一个,那么有两种方法,一种是用right 和 left 比较,如果相同就跳过,否则把 nums[right] 往前挪,第二种是用 right 跟 right-1 比较,如果相同,说明出现重复,跳过,否则同样把nums[right] 往前挪。理解上可能后边的稍微好理解一些。

第一种方法:
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        left, right = 0, 1
        while right < len(nums):
            if nums[right] != nums[left]:
                left += 1
                nums[left] = nums[right]
            right += 1
        return left + 1
第二种方法:(后来发现这种也是歪打正着)
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        left, right = 0, 1
        while right < len(nums):
            if nums[right] != nums[right - 1]:
                left += 1
                nums[left] = nums[right]
            right += 1
        return left + 1

其实这两种方法是一样的, nums[right - 1] 跟 nums[left] 一定是一相等的(只是可能不是同一个对象,不过值是一致的),因为我们总是把第一个出现的数往前挪,一个是比较挪之前的,一个是比较挪之后的,一个是跳过重复的,一个是维护去重序列。
虽然这边思路上好像没有问题,但是却犯了一个非常严重的指针错误,就是方法二比较前一个元素在 进行了 nums[left] = nums[right]这一步操作之后,可能 left 会把 right - 1或者right -2 覆盖了。所以去重的数组是可以保证完整的,而原数组却不能保证完整性,也许在该题是可以的,不过在下面这种情况却是不可以的。

2、删除有序数组中的重复项II

该题稍微进行了些升级,就是原先的去重现在不能超过两次。
其实该题用第一题的思路也能解,不过这边只能用方法一解决,这里用第二种方法会出现内存被误操作的情况。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        leftidx = 1
        rightidx = 2
        n = len(nums)
        while rightidx < n:
            if nums[rightidx] != nums[leftidx - 1]:
                leftidx += 1
                nums[leftidx] = nums[rightidx]
            rightidx += 1
        return leftidx + 1

另外临界情况需要有意识的考虑进去,比如数组为空的情况,逐渐会养成比较好的编程习惯。