Python 如何合并两个列表并在';线性';时间

Python 如何合并两个列表并在';线性';时间,python,list,merge,Python,List,Merge,我有这个,它是有效的: # 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 bo

我有这个,它是有效的:

# 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
但是,我真的很想把这些东西学好。:)“线性”时间是什么意思?

意味着程序的运行时间与输入的长度成正比。在这种情况下,输入由两个列表组成。如果列表的长度是原来的两倍,那么程序运行的时间大约是原来的两倍。从技术上讲,我们认为算法应该是,其中n是输入的大小(在本例中是两个输入列表的长度之和)

这似乎是家庭作业,所以我不会给你答案。尽管这不是家庭作业,但我认为最好的方法是拿一支笔和一张纸,构建两个分类的小示例列表,然后手动找出如何合并这两个列表。一旦你弄明白了这一点,实现算法就是小菜一碟

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

意味着时间是一个函数,其中n-输入的项目数(列表中的项目)。
f(n)=O(n)表示存在常数x和y,使得x*n线性时间表示O(n)复杂度。您可以在此处阅读有关算法复杂性和大O符号的内容:。 您应该尝试合并这些列表,而不是在最终列表中获得它们之后,尝试逐渐合并它们-添加一个元素,确保结果已排序,然后添加下一个元素。。。这应该会给你一些想法。

线性意味着O(n)in,而你的代码使用了
sort()
,这很可能是
O(nlogn)

这个问题是在问这个问题。一个简单的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]
def合并(l,m):
结果=[]
i=j=0
总计=长(l)+长(m)
而len(结果)!=总数:
如果len(l)=i:
结果+=m[j:]
打破
elif len(m)=j:
结果+=l[i:]
打破
以利夫l[i]>>合并([1,2,6,7],[1,3,5,9])
[1, 1, 2, 3, 5, 6, 7, 9]

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

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

“大O”指定执行时间的上限。平均执行时间和下限有相关的符号,但“big O”是最受关注的符号

  • O(1)是常数时间-问题的大小无关紧要
  • O(logn)是一条很浅的曲线——随着问题的扩大,时间会增加一点
  • O(n)是线性时间-每增加一个单位意味着它需要一个大致恒定的额外时间。这张图(大致)是一条直线
  • 当问题变得更复杂时,O(n logn)曲线上升得更陡,但幅度不是很大。这是通用排序算法所能做的最好的事情
  • 当问题变得更复杂时,O(n平方)曲线向上的幅度更大。这对于较慢的排序算法(如冒泡排序)是典型的
最糟糕的算法被归类为“np难”或“np完全”,其中“np”表示“非多项式”-曲线比任何多项式更快变陡。指数时间很糟糕,但有些甚至更糟。这类事情仍然在做,但只针对非常小的问题

编辑如评论所示,最后一段是错误的。我的算法理论确实有一些漏洞,显然是时候检查一下我认为自己已经弄明白的东西了。同时,我不太确定如何更正那一段,所以请注意

对于合并问题,考虑两个输入列表已经排序。输出中的最小项必须是输入中的最小项。从二者中获取第一项并比较二者,然后将最小项放入输出中。把最大的放回原处。你做了大量的工作,处理了一件事。重复此操作,直到两个列表都已用尽


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

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

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


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

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
def merge_排序(L1、L2)
>>> 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]
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