LeetCode小白菜笔记[9]:Remove Element
27. Remove Element [Easy]
题目:Given an array and a value, remove all instances of that value in-place and return the new length. Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. The order of elements can be changed. It doesn’t matter what you leave beyond the new length.
Example:
Given nums = [3,2,2,3], val = 3,
Your function should return length = 2, with the first two elements of nums being 2.
这个题目是要求把等于指定值的元素从 list 中删掉,也是原位操作。最简单的考虑是每删除一个就把剩下的都左移一下。这样就可以满足要求。但是每删除一次都要对后面的元素左移即所有的右项向左项赋值操作,一次这样的操作所花的时间是与数组长度成比例的,因此不能采用。由于题目中说:THE ORDER OF ELEMENTS CAN BE CHANGED,也就是可以不保序,那么考虑每删除一个就将最末一个pop出来放到这个位置再比较,以此循环,直到这一位置的元素不在和val相同,即可以不被删,则继续检查下一个位置。实际上这个做法是将不被删除的集中到 list 的前面,遍历完 list 后(由于pop出许多末尾元素因此 idx 实际上一共取值数目等于删除指定值后的list的长度)。代码如下:
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
if not nums or (len(nums) == 1 and nums[0] == val):
return 0
idx = 0
while (idx < len(nums)):
if nums[idx] == val:
nums[idx] = nums[-1]
nums.pop()
else:
idx += 1
return idx
这里注意在pop最后元素放到被删除的元素时,需要先赋值再pop,以避免pop的元素正好就是现在idx指向的元素,换言之,就是最后一个数字需要删除时,赋值出现 index out of range 。如 nums[idx] = nums.pop(),先pop,若pop出去的元素就是 idx 上的值,那么nums[idx]超范围。而如果先赋值在pop,可以直接将最后一个被删除的数pop掉,从而使得 idx=len(nums) ,退出while循环。
结果如下:
solution区的方法:
维护两个pointer,其中 j 是 fast-runner,i 是 slow-runner,( i,j 都初始化为0)。j 每次都 +1 ,如果 j 指向需要留下的,就把它放到 i 指向的位置,并 i ++ ;否则pass 。这样如果没有需要删除的,相当于把自己放在自己位置,如果有要删除的,那么 j 跑得比 i 快,所以相当于用后面的要保留的值占据了要删除的值。
这个方法针对需要被删除的元素比较少的情况:呃,好像和我的思路一样。时间复杂度线性,而且实际的赋值运算的数量等于要remove的元素总数,所以说在要删除的元素少的时候更加有效率。
总结:
考虑特殊情况和边界情况,正确使用pop 。
THE END
2017/12/16 Sat 17:51