使用分治法从给定列表中查找第二小的数字
Posted
技术标签:
【中文标题】使用分治法从给定列表中查找第二小的数字【英文标题】:Finding the second smallest number from the given list using divide-and-conquer 【发布时间】:2013-10-25 07:11:35 【问题描述】:我正在努力解决这个问题..
给定一个包含 n 个数字的列表,我们想找到最小的和第二小的 列表中的数字。描述一个分治算法来解决这个问题。假设整数 k 的 n = 2^k。使用您的算法的比较次数应该 不超过 3n/2 - 2,即使在最坏的情况下。
我目前的解决方案是使用选择算法得到中位数,然后将列表分为L1(包含小于或等于中位数的元素)、R(中位数)、L2(包含所有大于中位数的元素)。这是正确的吗?如果是这样,我下一步该怎么做?
【问题讨论】:
天真的方法效果很好:与 current_lowest 进行比较,(可能)与 current_2nd_lowest 进行比较。 @wildplasser 我同意这样的预期时间很好,但该声明特别要求最坏情况下的性能。最坏的情况可能是 [0,x,x,x,x,x,x,x,x] 之类的东西,您必须检查 0 之后的每个元素的最低和 second_lowest。它也不是分而治之。 @OP 您当前的解决方案是完全正确的。 :) 只需像这样继续划分列表并继续对具有较小元素的子列表进行操作。基本上对 L1 进行递归调用,直到 L1 最终成为仅包含 2 个元素的列表。请注意,它与使用快速选择算法 (k = 2) 结合中位数算法来选择枢轴非常相似。这种方法有很多信息,而且很容易实现。唯一困难的部分是理解子程序partition
是如何工作的。
【参考方案1】:
请注意,中值选择算法使用 Θ(n) 比较,但这并不意味着它最多使用 3n/2 - 2 次比较。事实上,我认为它使用的更多,这可能会排除您的解决方案策略。
作为提示:将此问题视为为所有 2k 建立淘汰赛;每轮的获胜者(两个数字中较小的一个)进入下一轮。实现它需要多少次比较?接下来,请注意第二小的数字必须“丢失”到最小的数字。第二小数也是“输”到最小数的最小数。鉴于此,你能有效地找到第二小的数字吗?
希望这会有所帮助!
【讨论】:
"也是最大的数“输”到了最小的数。" - 我想你的意思是第二小的数字是输给最小数字的最小数字。 谢谢,我实际上并没有在你的帖子中得到这个想法。好的,这个大纲怎么样:如果 n==2 比较并返回第一个,第二个最小的。如果 n>2 minimum= call(i=1 to n/2), and minimum2= call(i=n/2 to n) 并返回最小值......这可行吗? @Faisal- 你将如何返回两半的最小值?另外,如果您不理解我的帖子,也许我应该编辑它。有什么特别的事情你没有得到吗? @Faisal- 不,没有合并排序。您是否了解如何为 2^n 名玩家组织一场锦标赛,以便确定谁是总冠军? 很遗憾,我不明白如何为 2^n 名玩家组织锦标赛。【参考方案2】:哦,我明白了(在 Python 中):
def two_min(arr):
n = len(arr)
if n==2: # Oops, we don't consider this as comparison, right?
if arr[0]<arr[1]: # Line 1
return (arr[0], arr[1])
else:
return (arr[1], arr[0])
(least_left, sec_least_left) = two_min(arr[0:n/2])
(least_right, sec_least_right) = two_min(arr[n/2:])
if least_left < least_right: # Line 2
least = least_left
if least_right < sec_least_left: # Line 3
return (least, least_right)
else:
return (least, sec_least_left)
else:
least = least_right
if least_left < sec_least_right: # Line 4
return (least, least_left)
else:
return (least, sec_least_right)
总共:
第 1 行:将有准确的 n/2
比较
第 2 行:这里会有 n/4 + n/8 + ... + 1
比较
第 3 行和第 4 行:每次调用 two_min
时将执行其中的一个(除非使用两个元素调用它)。我们总共调用了two_min
次n-1
(因为有那么多锦标赛),其中n/2
被两个元素调用。所以第 3 行和第 4 行有助于n/2 - 1
比较
结合所有这些,我们有:
total_comparisons = n/2 + (n/4 + n/8 + ... + 1) + (n/2 - 1)
= (n - 1) + (n/2 - 1)
= 3n/2 - 2
【讨论】:
非常感谢您的帮助。以上是关于使用分治法从给定列表中查找第二小的数字的主要内容,如果未能解决你的问题,请参考以下文章