在python中将所有零移动到数组的末尾
Posted
技术标签:
【中文标题】在python中将所有零移动到数组的末尾【英文标题】:Move all zeros to the end of the array in python 【发布时间】:2021-03-22 03:37:36 【问题描述】:给定一个数组 nums,我试图将所有 0 移到它的末尾,同时保持非零元素的相对顺序。我正在尝试在不复制数组的情况下就地执行此操作。
所以对于输入 [0,1,0,3,12],输出应该是 [1,3,12,0,0]。但是我下面的代码只能将数组中的第一个零移动到数组的末尾,并给出错误的输出 [1,0,3,12,0]。如何修改它以便所有零有效地移动到数组的末尾?
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n=len(nums)
for i in range(0,n):
if (nums[i]==0) and ((i+1)<n):
nums[i]=nums[i+1]
nums[i+1]=0
print(nums)
【问题讨论】:
【参考方案1】:让我做你的功课:-)
n = len(nums)
j = 0
for i in range(n):
nums[j] = nums[i]
j += 1 if nums[i] else 0
nums[j:] = [0] * (n-j)
如果你的头脑足够理解它,你至少会学到一些东西......
【讨论】:
【参考方案2】:Python 的内置排序是稳定排序,这意味着元素只有在根据您用于排序的标准不同时才会被交换。
要使用排序将所有零移到末尾,我们必须找到一个零总是大于任何其他值的变换,但这很容易...... Python 布尔值是有序的,True
更大而不是False
,所以我们的魔法转换就是n==0
!
演示:
In [1]: sorted([0,1,0,3,12], key=lambda n: n==0)
Out[1]: [1, 3, 12, 0, 0]
如果您想避免复制,请使用列表的.sort
方法。
l = [0,1,0,3,12]
l.sort(key=lambda n:n==0)
【讨论】:
经过深思熟虑后,我想我猜想当 l.sort(ky=lambda n: n==0) 在列表 L -> [False, True, False, True, True] -> 所以我们得到了将所有 False('零')移动到末尾的预期结果。非常聪明。 @DanielHao 抱歉,我没有回复您的第 1 条评论(意大利的睡觉时间……),但我看到您说得对!【参考方案3】:两指针算法
这是时间复杂度为 O(N) 且没有辅助空间的解。
def move_zeros(data: list) -> list:
size = len(data)
left = right = 0
while right < size:
if data[right] == 0:
right += 1
else:
data[left], data[right] = data[right], data[left]
right += 1
left += 1
return data
if __name__ == "__main__":
arr = [1, 2, 0, 0, 3, 4, 0, 0, 0, 7, 2, 4]
print(move_zeros(data=arr))
输出:
[1, 2, 3, 4, 7, 2, 4, 0, 0, 0, 0, 0]
【讨论】:
【参考方案4】:list(filter(lambda x: x!= 0, array))+[0]*array.count(0)
或
[x for x in array if x !=0]+[0]*array.count(0)
【讨论】:
OP 专门要求就地修改列表,因此虽然这看起来是一个很好、简单的解决方案,但它并不能回答问题。【参考方案5】:您的问题是,在第一步之后,您有两个相邻的零。您交换零,然后将 0 留在 [1] 位置,永远不要回到后面
相反,我建议您迭代数组并保留最后一个非零数 j 的跟踪器,初始化为 -1。您可以将遇到的任何非零值交换为 j+1。之后 0 的顺序无关紧要。
旁注:在 python 中,range(n) 将迭代 0 -> n-1,因此您不需要 and 语句中的第二个条件来终止循环。相反,你可以做 range(n-1),例如
【讨论】:
【参考方案6】:使用列表推导将列表划分为 2 个列表,然后按所需顺序连接它们:
orig_lst = [0, 1, 0, 3, 12]
lst_non0 = [x for x in orig_lst if x != 0 ]
lst_0 = [x for x in orig_lst if x == 0 ]
lst_0s_at_end = lst_non0 + lst_0
print(lst_0s_at_end)
# [1, 3, 12, 0, 0]
您也可以通过就地更改原始列表来获得相同的结果:
orig_lst = [0, 1, 0, 3, 12]
orig_lst = [x for x in orig_lst if x != 0 ] + [x for x in orig_lst if x == 0 ]
【讨论】:
他说:“我正在尝试就地执行此操作,而不复制数组。”【参考方案7】:一个人可以只remove
零,同时计算它们,然后在原始列表的剩余部分附加我们之前删除的零...
>>> help(list.remove)
Help on method_descriptor:
remove(self, value, /)
Remove first occurrence of value.
Raises ValueError if the value is not present.
>>> import random
>>> c, l = 0, [random.randint(0, 10) for _ in range(100)]
>>> while True:
... try:
... l.remove(0)
... c += 1
... except ValueError:
... break
>>> l += [0]*c
【讨论】:
这个解决方案将花费二次时间,因为l.remove(0)
需要线性时间,必须移动所有元素。【参考方案8】:
这个想法是使用删除函数删除列表中所有出现的零,并维护一个计数变量来计算零出现的次数,最后多次附加零“计数”。我希望这是一个有效的解决方案对于您的问题。请找到相同的代码:
lis = [1,2,0,5,6,0,6,0,7]
count = 0
for i in lis:
if(i==0):
lis.remove(i)
count = count+1
for i in range(count):
lis.append(0)
print(lis)
【讨论】:
【参考方案9】:可以使用python的sorted函数对数组进行排序,保持反转为True。那里也给出了第二种方法。
# one way
array42 = [0, 5, 2,0,0,5,2,7,0,2,3]
print(sorted(array42))
# second way
index = len(array42)-1
for i in range(len(array42)-1,-1,-1):
if array42[i]!=0:
array42[index]=array42[i]
index -= 1
for i in range(index,-1,-1):
array42[index]=0
index -= 1
print(array42)
【讨论】:
【参考方案10】:解决此问题的另一种方法:(向后工作 - 它也可以应用于迭代和处理时的一般情况,通常不推荐)。 时间方面的比较 - @gboffi 更好 O(log N),而这个是 O(N)。
def moveZeros(A):
for i in range(len(A)-1, -1, -1):
if not A[i]: # num. is 0
del A[i]
append(0)
【讨论】:
这个解决方案是 O(N^2),而不是 O(N),因为每个del
调用都必须在 A[i]
之后移动所有数据。 @gboffi 的解决方案是 O(N log N),因为它使用排序。
同意。这是演示的一种方法。【参考方案11】:
这个问题有足够的答案,我不知道为什么我觉得有必要再补充一个,但我是。我的解决方案基本上等同于@Cabu,基于您不需要存储您移动的那些 0 的认识,因为它们都是相同的。相反,您可以在数组上循环一次时覆盖它们,并在最后写入正确数量的零。
def moveZeroes(nums) -> None:
pos = 0 # keep track of where to place the next non-zero value
for num in nums:
if num != 0:
nums[pos] = num
pos += 1
for i in range(pos, len(nums)):
nums[i] = 0
我发布这个额外的解决方案是因为
我更喜欢尽量减少索引的使用:使用for num in nums:
而不是 for i in range(n):
。
我避免在第二个循环中创建一个临时的 0 列表。
因此,此解决方案可能(未经测试,但至少微不足道)更有效:此代码在线性时间内运行并且不需要额外的存储空间。
话虽如此,如果必须保留“零”值,因为它们在某些方面有所不同,我首选的解决方案是@Soumya 提出的双指针算法。它还以线性时间运行并避免任何临时存储。但是,它会打乱那些零,所以如果零的顺序很重要,它就不会按原样工作。
【讨论】:
以上是关于在python中将所有零移动到数组的末尾的主要内容,如果未能解决你的问题,请参考以下文章
将给定数组中的所有零移动到末尾,并将每个非零元素替换为最接近的较大值(如果有)
2021-10-31:移动零。给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。示例:输入: [0,1,0,3,12]。输出: [1,3,12,0,0]。说
Leetcode 数组:283 removezeros 移动零(python)