题目描述
其实一开始看题目是比较懵逼的,什么叫不要使用额外的数组空间,就是要再原来的数组上做变换。
一开始的想法比较曲折,一开始想用for去遍历做,结果发现不行,后来用while就勉强做了出来。
先初始化
i
=
0
i =0
i=0 ,如果
n
u
m
s
[
0
]
nums[0]
nums[0]和
n
u
m
s
[
1
]
nums[1]
nums[1]两个是不同的,不用管它,直接
i
=
i
+
1
i=i+1
i=i+1 ,一开始其实陷入了一个误区,我以为如果前后两个不同,
i
i
i应该跳到
3
3
3,而不是跳到
2
2
2,但其实第一个和第二个不同,并不能直接去比较第三个和第四个是不是不同,也有可能是第二个和第三个是相同的,也就是说,如果遍历的话,必须比较
n
−
1
n-1
n−1次。所以如果前后的值不同,
i
=
i
+
1
i=i+1
i=i+1,如果前后相同,把后面的那个值pop掉,同时不改变
i
i
i的值
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
i = 0
while i < len(nums)-1:
if nums[i] != nums[i+1]:
i = i + 1
else:
nums.pop(i+1)
return len(nums)
看了大神的答案觉得非常妙,和大家分享一下。
之前说为什么正着去遍历不能用for呢?
因为你相同的时候,后面的那个被pop掉了,但是
i
i
i的坐标没变,但是如果用for,
i
i
i每次都要+1,所以只能用while了。
但是逆遍历就不一样了,它可以防止删除某个元素后影响下一步索引的定位,因为你pop掉之后不影响前面的值的下标,所以尽管往前去比较两个值就可以了,相同就把下标大的那个pop掉就可以了,非常妙。
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
for i in range(len(nums)-1, 0, -1):
if nums[i] == nums[i-1]: nums.pop(i)
return len(nums)
还有一种官方的解法,也非常神奇,更加有技巧。
数组完成排序后,我们可以放置两个指针
i
i
i 和
j
j
j,其中
i
i
i 是慢指针,而
j
j
j 是快指针。只要
n
u
m
s
[
i
]
=
n
u
m
s
[
j
]
nums[i] = nums[j]
nums[i]=nums[j],我们就增加
j
j
j 以跳过重复项。当我们遇到
n
u
m
s
[
j
]
!
=
n
u
m
s
[
i
]
nums[j] != nums[i]
nums[j]!=nums[i]时,跳过重复项的运行已经结束,因此我们必须把它(
n
u
m
s
[
j
]
nums[j]
nums[j])的值复制到
n
u
m
s
[
i
+
1
]
nums[i + 1]
nums[i+1]。然后递增
i
i
i,接着我们将再次重复相同的过程,直到
j
j
j 到达数组的末尾为止。
也就是遇到一样的值,就跳过,直到遇到不同的值,就让该值赋给 n u m s [ i + 1 ] nums[i+1] nums[i+1],这样保证了 n u m s [ i ] nums[i] nums[i] 和 n u m s [ i + 1 ] nums[i+1] nums[i+1] 是不同的,这样 j j j 是一直扫描的, j j j就继续往后扫描,遇到不同的就赋值给 n u m s [ i + 2 ] nums[i+2] nums[i+2],所以你的填补的位置要变,所以让 i = i + 1 i = i + 1 i=i+1
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
i = 0
for j in range(1, len(nums)):
if nums[j] != nums[i]:
nums[i + 1] = nums[j]
i += 1
return i + 1 if nums else 0