题目快速通道
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
另外临界情况需要有意识的考虑进去,比如数组为空的情况,逐渐会养成比较好的编程习惯。