关于谷歌Python课程的解决方案问题

1 投票
4 回答
1188 浏览
提问于 2025-04-16 16:42

嘿,

我正在学习一些Python,所以决定跟着谷歌的教程来学。不过我对他们一个练习的解法有个问题。

我这样做的。

# 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):
  # +++your code here+++
  return sorted(list1 + list2)

但是他们的做法要复杂一些。那么,谷歌的解法更快吗?因为我注意到评论里提到这个解法应该是“线性”时间的,而我的可能不是?

这是他们的解法。

def linear_merge(list1, list2):
  # +++your code here+++
  # LAB(begin solution)
  result = []
  # Look at the two lists so long as both are non-empty.
  # Take whichever element [0] is smaller.
  while len(list1) and len(list2):
    if list1[0] < list2[0]:
      result.append(list1.pop(0))
    else:
      result.append(list2.pop(0))

  # Now tack on what's left
  result.extend(list1)
  result.extend(list2)
  return result

4 个回答

0

我觉得这里的问题在于,这个教程是在教你怎么用Python实现一个叫做“合并”的著名算法。教程并不希望你在解决方案中使用库里的排序函数。

sorted() 函数的复杂度大概是 O(nlgn),所以在最坏情况下,你的解决方案不可能是线性的。

理解 merge() 是怎么工作的很重要,因为它在很多其他算法中都很有用。这个算法利用了输入列表已经排好序的特点,依次遍历每个列表,选择最小的那个。剩下的项会被加到最后面。

问题并不是哪个算法对特定输入更“快”,而是哪个算法更复杂。

还有一些混合版的合并排序算法,当输入列表的大小低于某个阈值时,会切换到其他排序算法。

2

这可能是另一种解决方案?

    def linear_merge(list1, list2):
            tmp = []
            while len(list1) and len(list2):
                    #print list1[-1],list2[-1]
                    if list1[-1] > list2[-1]:
                            tmp.append(list1.pop())
                    else:
                            tmp.append(list2.pop())
                    #print "tmp = ",tmp

            #print list1,list2
            tmp = tmp + list1
            tmp = tmp + list2
            tmp.reverse()
            return tmp
1

你的算法不是线性的,但这并不意味着它就一定更慢。算法的复杂度(也就是“大O表示法”)通常只是一个粗略的参考,它只能告诉你故事的一部分。

不过,他们的算法也不是线性的,虽然乍一看可能会觉得是。因为从列表中弹出一个元素时,需要移动后面的所有元素,所以从前面弹出一个元素时,就需要移动所有剩下的元素。

想一想如何把这个复杂度降低到O(n)是个不错的练习。下面的内容和给出的解决方案有相似之处,但避免了一些陷阱,同时为了练习扩展到不止两个列表。如果只有两个列表,你可以不使用堆,而是直接比较哪个下一个元素更小。

import heapq

def iter_linear_merge(*args):
  """Yield non-decreasing items from sorted a and b."""
  # Technically, [1, 1, 2, 2] isn't an "increasing" sequence,
  # but it is non-decreasing.

  nexts = []
  for x in args:
    x = iter(x)
    for n in x:
      heapq.heappush(nexts, (n, x))
      break

  while len(nexts) >= 2:
    n, x = heapq.heappop(nexts)
    yield n
    for n in x:
      heapq.heappush(nexts, (n, x))
      break

  if nexts:  # Degenerate case of the heap, not strictly required.
    n, x = nexts[0]
    yield n
    for n in x:
      yield n

在最后的if-for循环中,while循环的条件可以改成只检查“nexts”,但特别处理最后一个迭代器可能还是值得的。

如果你想严格返回一个列表而不是迭代器:

def linear_merge(*args):
  return list(iter_linear_merge(*args))

撰写回答