【问题标题】:How does the time complexity of iterating through two unsorted list of integers compare to sorting then iterating through the lists?遍历两个未排序的整数列表的时间复杂度与排序然后遍历列表相比如何?
【发布时间】:2021-09-06 22:52:42
【问题描述】:

这个问题是关于两种算法的时间复杂度

所以我正在解决一个涉及两个整数列表(未排序)的问题,我想返回具有最小绝对差的整数对(每个列表中的一个)。。 p>

  1. 简单的方法是简单地遍历两个列表,并始终跟踪最小的差异,最后返回产生这种差异的对 - 我相信这需要O(mn) time,其中 n 和 m 是每个列表的长度;因为我们只是使用2x for loops

  2. 另一种方法是 sort 两个列表,然后遍历它们,并且有一些逻辑可以在许多情况下打破 for 循环,而无需遍历整个第二个列表。我相信这需要O(nlogn + mlogm) time,同样,n,m 是两个列表的长度。

我在解决方案页面上读到解决方案 2. 更有效,但我不明白为什么?- 如果我上面提到的时间复杂度是正确的,对于解决方案 2。如果我们通过 mn 分解剩下的内容 > 0??

【问题讨论】:

  • 请不要使用code blocks for emphasis...
  • 抱歉,没注意到

标签: python time-complexity


【解决方案1】:

我们可以通过一个例子更好地看到差异。假设我们有 2 个列表,每个列表包含从 1 到 100 的 100 项列表。

  • list1 = [11, 2, 33, 4, 5, 67, ...] = n n 为 100 的项目
  • list2 = [8, 90, 1, 23, 45, 7, ...] = m m 为 100 的项目

天真的方法

步骤:

  • 遍历 list1 的 n 项目的每个元素
    • 时间复杂度:n = 100
  • 对于上述每次迭代,迭代list2 的m 项的每个元素,只是为了获得与list1 的当前项产生最小差异的数字。
    • 时间复杂度:n * m = 100 * 100 = 10,000

总时间复杂度:n * m = 10,000

排序数据方法1

步骤:

  • 排序list2 产生[1, 2, 3, 4, 5, ...]
    • 时间复杂度:m * log(m) = 100 * log(100) = 664.4 = ~700
  • 遍历 list1 的 n 项目的每个元素
    • 时间复杂度:n = 100
  • 对于上述每次迭代,对list2 的排序项执行binary search 以查看list1 的当前项最接近的位置。
    • 为了进一步解释这一点,假设我们有一个排序的 8 项列表[0, 5, 10, 15, 20, 25, 30, 35]
    • 如果我们要搜索最接近值的数字是22,我们不需要遍历整个列表。就像字典/词库一样,如果您要查找单词“Potato”,您将不会从第 1 页浏览字典,您会做的是转到中间,如果它低于“P”,例如“M”则走得更远,但如果更高,例如“S”,则返回,然后重复。
    • 所以我们要检查的项目是中间的15,然后是25,然后是20。这 3 项证明了 log(n) = log(8) = 3 的二分查找时间复杂度,因为我们每一步都将列表一分为二。
    • 一旦我们在20,我们可以检查周围的数字,即[15, 20, 25],看看最接近22,这将是20,因此它是配对以获得最小差异的数字。这只是一个常量O(1) 操作。
    • 时间复杂度:n * log(m) = 100 * log(100) = 664.4 = ~700

总时间复杂度:(m * log(m)) + (n * log(m)) = 700 + 700 = 1,400

排序数据方法2

  • 排序list1 产生[1, 2, 3, 4, 5, ...]
    • 时间复杂度:n * log(n) = 100 * log(100) = 664.4 = ~700
  • 排序list2 产生[1, 2, 3, 4, 5, ...]
    • 时间复杂度:m * log(m) = 100 * log(100) = 664.4 = ~700
  • 同时遍历list1list2 以了解哪一对会产生最小的差异。移动具有较小值的迭代器。这个想法就像 2 个人通过楼梯向上搬运木头,较低的人将向上移动,以保持同步,并且 2 人始终保持彼此最近的距离(否则木头将跌倒^_^)。
    • 时间复杂度:n + m = 100 + 100 = 200

总时间复杂度:(n * log(n)) + (m * log(m)) + n + m = (n * log(n)) + (m * log(m)) = 700 + 700 = 1,400

  • n + m 已被删除,因为它们是非主导词

结论

对于每个大小为 100 的 2 个列表,排序数据方法比简单方法快约 8,600 次迭代。

【讨论】:

  • 你不需要二分查找;只需维护两个索引变量,一个用于每个排序列表,然后迭代地推进在当前索引处具有较低值的列表中的索引。像合并排序的工作原理一样思考,除了您不需要将合并结果实际输出为新列表。 (如果有平局,那么您发现一个列表中的元素与另一个列表中的元素相等,因此最小绝对差为 0,您可以终止。)
  • 哦,我明白了。尽管我相信这与我所写的方法不同,因为我没有对其中一个列表进行排序:) 我会尝试使用对 2 个列表进行排序的方法进行更新。感谢您的评论:)
  • 在我看来,它在代数上也是一致的。您提到了 O(nm)O(nlogn + mlogm) 的 2 个时间复杂度。如果我们将值100200 分别替换为nm,我们将得到O(nm) = 100 * 200 = 20,000O(nlogn + mlogm) = 100(log(100)) + 200(log(200)) = 664.4 + 1,528.8 = 2,173.2。因此,O(nm) 确实高于O(nlogn + mlogm),这在我的回答中的给定示例中也得到了证明。
  • 绝对不是更高;考虑m 保持不变的情况,并考虑nm 相等的情况。
  • @kaya3 细微的变化:将所有内容放在一个列表中,如果 neighbors 来自不同的列表,则找出它们的最小差异。 Demo.
【解决方案2】:

让我们稍微简化一下方程式,假设:n = m

  1. 第一种情况,复杂度为:n * m = n^2
  2. 第二种情况,复杂度为:n * log(n) + m * log(m) = 2 * n * log(n)

对于任何现有的 n,您有 2*log(n)

【讨论】:

    猜你喜欢
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2012-12-14
    • 2017-06-02
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多