【问题标题】:Move all zeros to the end of the array in python在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) 

【问题讨论】:

    标签: python arrays python-3.x


    【解决方案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 提出的双指针算法。它还以线性时间运行并避免任何临时存储。但是,它会打乱那些零,所以如果零的顺序很重要,它就不会按原样工作。

              【讨论】:

                猜你喜欢
                • 2021-10-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-07-19
                • 1970-01-01
                • 2021-09-09
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多