【问题标题】:list pop and insert are very slow in python列表弹出和插入在python中非常慢
【发布时间】:2021-12-14 20:42:37
【问题描述】:

我正在做一个 leetcode 问题 189. Rotate Array。

问题陈述: 给定一个数组,将数组向右旋转 k 步,其中 k 为非负数。 输入:nums = [1,2,3,4,5,6,7], k = 3 输出:[5,6,7,1,2,3,4]

以下是我的代码。我的理解是时间复杂度是 O(k),但它最终非常低。能否请您对此有所了解并教育我?

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        while k:
            nums.insert(0,nums.pop())
            k -= 1 

【问题讨论】:

  • 您可能需要考虑一种不同的方法,它不会在每一步都修改数组,但请考虑如何重新索引要像这样移动的数组。
  • 非常慢是什么意思?这里没有太多会导致真正的性能问题
  • 无论哪种方式 - CPython 中的列表都是作为简单的指针数组实现的,因此弹出很简单,但在 0 处插入需要将所有内容向右移动并设置第一个条目。
  • 列表不适合这个insert(0)(到头)操作。最好考虑其他方式来处理更大的列表。
  • @AlbertGLieu 不,绝对不是。对于典型的用例,链表将是灾难性的,它被实现为一个数组列表,这就是为什么访问是恒定时间的,即mylist[0]mylist[10_000] 花费相同的时间通常,只有在默认实现时您会看到链表的地方是函数式编程语言,即“缺点列表”。

标签: python list


【解决方案1】:

一种方法是使用双端队列rotate,如下所示

from collections import deque
from typing import List

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        dnums = deque(nums)
        dnums.rotate(k)
        nums[:] = dnums


nums = [1,2,3,4,5,6,7]
Solution().rotate(nums, 3)
print(nums)

输出

[5, 6, 7, 1, 2, 3, 4]

来自文档(重点是我的):

将双端队列向右旋转 n 步。如果 n 是负数,旋转到 左边。当双端队列不为空时,旋转一步到 right 等价于d.appendleft(d.pop()),旋转一 step to left 相当于 d.append(d.popleft())。

在列表开头插入的问题是它是 O(n),你必须移动所有元素。在开头插入的双端队列(appendleft)是 O(1)。

更多关于deque和list的时间复杂度,见here

【讨论】:

  • 这是一种选择,但我很确定也有一种简单的nums[:] = [nums[(i + shift % ... 方法来解决这个问题:-)
  • 感谢 Dani 的解决方案,我主要想了解为什么我的代码与其他代码相比如此缓慢。你知道为什么吗?
  • 但这并不比 pop/append 解决方案快。
  • @TimRoberts 你为什么这么说?
  • @juanpa.arrivillaga 计算要求相同分配内存,复制元素,添加新元素。一个是隐式的,一个是显式的,但时间应该是一样的。
【解决方案2】:

Deque 是很好的 DS。或者,你可以试试这个: 这被接受并在 Python 类别中排名 88%。 (速度和deque差不多)

[注意]列表长度为10^5。它要求in-place ops。

 def rotate(self, nums: List[int], k: int) -> None:
     """
     Do not return anything, modify nums in-place instead.
     """
     z = len(nums)
     k = k % z
        
     nums[:] = nums[z-k:] +nums[:z-k]

【讨论】:

  • 简单和pythonic。这是非常有用的。
【解决方案3】:

仅供参考,如果您使用numpy

import numpy as np

nums = [1, 2, 3, 4, 5, 6, 7]
k = 3

print(np.roll(nums, k).tolist())

# Output:
[5, 6, 7, 1, 2, 3, 4]

【讨论】:

  • 遗憾的是,在 Leetcode 中不推荐使用 numpy
猜你喜欢
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 2021-02-12
相关资源
最近更新 更多