【问题标题】:How can I merge two lists and sort them working in 'linear' time?如何合并两个列表并在“线性”时间内对它们进行排序?
【发布时间】:2023-03-12 09:44:01
【问题描述】:

我有这个,它可以工作:

# E. Given two lists sorted in increasing order, create and return a merged
# list of all the elements in sorted order. You may modify the passed in lists.
# Ideally, the solution should work in "linear" time, making a single
# pass of both lists.
def linear_merge(list1, list2):
  finalList = []
  for item in list1:
    finalList.append(item)
  for item in list2:
    finalList.append(item)
  finalList.sort()
  return finalList
  # +++your code here+++
  return

但是,我真的很想好好学习这些东西。 :) “线性”时间是什么意思?

【问题讨论】:

  • 不,这是我在业余时间运行的 Google Python 教程。
  • 你可能想看看算法,这与python无关。这称为合并。暂时忘记python,如何合并两个非单调递增的排序列表。您可以查看合并排序以更好地理解这一点。即使是插入排序也可以做到这一点,您也可以使用二进制插入。

标签: python list merge


【解决方案1】:

Linear time 表示程序的运行时间与输入的长度成正比。在这种情况下,输入由两个列表组成。如果列表的长度是原来的两倍,那么程序将运行大约两倍的时间。从技术上讲,我们说算法应该是O(n),其中 n 是输入的大小(在这种情况下是两个输入列表的总长度)。

这似乎是家庭作业,所以我不会为您提供答案。即使这不是家庭作业,我认为最好还是拿一支笔和一个一张纸,构建两个排序的小示例列表,并弄清楚 you 如何手动合并这两个列表。一旦你弄清楚了,实现算法就是小菜一碟。

(如果一切顺利,您会注意到您只需要在一个方向上迭代每个列表一次。这意味着该算法确实是线性的。祝您好运!)

【讨论】:

  • @Sergio Tapia 但无论如何这是一个不错的答案。
  • 对理论很有用,但它并没有在代码中解释如何实现一些记住这一点的东西。
  • @Sergio:对不起,我回答时还不清楚。无论如何,我认为这是最好自己解决的练习。从长远来看,这样做会更有回报和有益。
【解决方案2】:

'Linear time' 表示时间是一个O(n) 函数,其中 n - 输入的项目数(列表中的项目)。
f(n) = O(n) 表示存在常数 x 和 y 使得 x * n

def linear_merge(list1, list2):
  finalList = []
  i = 0
  j = 0
  while i < len(list1):
    if j < len(list2):
      if list1[i] < list2[j]:
        finalList.append(list1[i])
        i += 1
      else:
        finalList.append(list2[j])
        j += 1
    else:
      finalList.append(list1[i])
      i += 1
  while j < len(list2):
    finalList.append(list2[j])
    j += 1
  return finalList

【讨论】:

    【解决方案3】:

    线性时间意味着 O(n) 复杂度。您可以在此处阅读有关算法复杂性和大 O 表示法的内容:http://en.wikipedia.org/wiki/Big_O_notation。 您应该尝试组合这些列表,而不是在将它们放入 finalList 之后,尝试逐渐合并它们 - 添加一个元素,确保结果已排序,然后添加下一个元素......这应该会给您一些想法。

    【讨论】:

      【解决方案4】:

      线性表示Big O notation 中的 O(n),而您的代码使用 sort(),这很可能是 O(nlogn)。

      问题是要求standard merge algorithm。一个简单的 Python 实现是:

      def merge(l, m):
          result = []
          i = j = 0
          total = len(l) + len(m)
          while len(result) != total:
              if len(l) == i:
                  result += m[j:]
                  break
              elif len(m) == j:
                  result += l[i:]
                  break
              elif l[i] < m[j]:
                  result.append(l[i])
                  i += 1
              else:
                  result.append(m[j])
                  j += 1
          return result
      
      >>> merge([1,2,6,7], [1,3,5,9])
      [1, 1, 2, 3, 5, 6, 7, 9]
      

      【讨论】:

      • 请注意,由于您使用.pop(0),因此您的算法实际上是二次的(如果l 和m 是列表)。线性替换将跟踪索引或使用iter(l) 和iter(m) 并使用next 而不是pop(0)。
      • @Mike:你是对的。修复已编辑。为常见数据结构提供方便的 API 可以真正让人们对明显的低级问题不敏感。
      • 非常非常有趣的方法。在我看来很优雅。
      【解决方案5】:

      线性时间意味着所花费的时间受一些未定义的常数时间(在此上下文中)要合并的两个列表中的项目数的限制。您的方法没有实现这一点 - 它需要 O(n log n) 时间。

      当根据问题大小指定算法需要多长时间时,我们会忽略机器速度等细节,这基本上意味着我们忽略了所有常数项。为此,我们使用“渐近符号”。这些基本上描述了您将在 x 中的问题大小与 y 中所用时间的图表中绘制的曲线的 形状。逻辑是,如果问题足够大,一条糟糕的曲线(快速变陡的曲线)总是会导致执行时间变慢。对于一个非常小的问题(取决于常量,这可能取决于机器),它可能会更快,但对于小问题,执行时间通常不是一个大问题。

      “大 O”指定了执行时间的上限。平均执行时间和下限有相关的表示法,但“大 O”是最受关注的一种。

      • O(1) 是常数时间 - 问题大小无关紧要。
      • O(log n) 是一条很浅的曲线 - 随着问题的增大,时间会稍微增加。
      • O(n) 是线性时间 - 每增加一个单位意味着它需要大致恒定的额外时间。该图(大致)是一条直线。
      • 随着问题变得更加复杂,O(n log n) 曲线向上更陡峭,但幅度不大。这是通用排序算法所能做到的最好的。
      • 随着问题变得更加复杂,O(n squared) 曲线向上陡峭得多。这对于冒泡排序等较慢的排序算法来说很典型。

      最讨厌的算法被归类为“np-hard”或“np-complete”,其中“np”表示“非多项式”——曲线变得比任何多项式都更快。指数时间很糟糕,但有些甚至更糟。这类事情仍在进行,但仅限于非常小的问题。

      EDIT最后一段是错误的,如评论所示。我的算法理论确实存在一些漏洞,显然是时候检查我认为我已经弄清楚的事情了。同时,我不太确定如何更正该段,因此请注意。

      对于您的合并问题,请考虑您的两个输入列表已经排序。输出中最小的项目必须是输入之一中的最小项目。从两者中获取第一项并比较两者,然后将最小的放入输出中。把最大的放在它来自的地方。你已经完成了大量的工作并且你已经处理了一个项目。重复直到两个列表都用完为止。

      一些细节...首先,将项目放回列表中只是为了再次将其拉回显然是愚蠢的,但它使解释更容易。接下来 - 一个输入列表将在另一个之前用尽,因此您需要处理它(基本上只需清空另一个列表的其余部分并将其添加到输出中)。最后 - 您实际上不必从输入列表中删除项目 - 同样,这只是解释。您可以单步执行。

      【讨论】:

      • NP 并不意味着“非多项式”。它代表“非确定性多项式”,意味着非确定性图灵机可以在多项式时间内解决问题。不是每个不在 P 中的问题都在 NP 中(P 中的每个问题也在 NP 中),即存在无法通过非确定性图灵机在多项式时间内解决的问题。 (无论如何+1,因为关于 NP 的部分与手头的问题并不真正相关,而帖子的其余部分非常好)。
      【解决方案6】:

      此线程包含线性时间合并算法的各种实现。请注意,出于实际目的,您将使用heapq.merge。

      【讨论】:

        【解决方案7】:

        如果您以反向排序顺序构建结果,您可以使用 pop() 并且仍然是 O(N)
        pop() 从列表的右端开始不需要移动元素,O( 1)
        在我们返回之前反转列表是 O(N)

        >>> def merge(l, r):
        ...     result = []
        ...     while l and r:
        ...         if l[-1] > r[-1]:
        ...             result.append(l.pop())
        ...         else:
        ...             result.append(r.pop())
        ...     result+=(l+r)[::-1]
        ...     result.reverse()
        ...     return result
        ... 
        >>> merge([1,2,6,7], [1,3,5,9])
        [1, 1, 2, 3, 5, 6, 7, 9]
        

        【讨论】:

        • +1 非常酷的解决方案。从来没有在任何一本书中看到过这样的合并:-)。
        【解决方案8】:

        一个更简单的版本,需要相同大小的列表:

        def merge_sort(L1, L2):
           res = [] 
           for i in range(len(L1)):
              if(L1[i]<L2[i]):
                  first = L1[i]  
                  secound = L2[i] 
              else:
                  first = L2[i]  
                  secound = L1[i]  
              res.extend([first,secound]) 
           return res
        

        【讨论】:

          【解决方案9】:

          itertoolz 提供了一个有效的实现来合并两个排序列表 https://toolz.readthedocs.io/en/latest/_modules/toolz/itertoolz.html#merge_sorted

          【讨论】:

            猜你喜欢
            • 2022-10-04
            • 1970-01-01
            • 1970-01-01
            • 2023-03-18
            • 1970-01-01
            • 2016-09-23
            • 1970-01-01
            • 1970-01-01
            • 2021-10-18
            相关资源
            最近更新 更多