【问题标题】:Finding the highest 2 numbers- computer science寻找最高的 2 个数字 - 计算机科学
【发布时间】:2009-10-30 10:16:55
【问题描述】:

我正在尝试找出一种算法来查找数字列表中最高的 2 个数字。

最大的数字可以在 n-1 个阶段中找到,可能是通过冒泡排序的第一步或类似的方式。对我来说,似乎在平均总共 1.5n 次比较中也可以找到下一个最高的数字。

我的教授给我们布置了作业,让我们编写一个算法,在 n + log(n) 比较中找到最高的 2 个数字。这甚至可能吗?有什么想法、建议吗?

编辑:当我说 n + log(n) 时,我指的不是 O(n + log n),而是确切地说是 n + log n

【问题讨论】:

  • 见问题编号。 1602998
  • 这里有一个方便的链接:stackoverflow.com/questions/1602998
  • 数字必须不同吗?例如。在列表 (1, 3, 2, 3) 中,两个最高的数字是 (3, 3) 还是 (2, 3)?
  • @jonB- 为了争论的缘故,我们假设这些数字都是不同的
  • @Niels 我刚刚仔细查看了该问题和答案,但我看不到任何可以帮助我实现 n + log n 结果的东西。你能说得更具体点吗?

标签: algorithm computer-science


【解决方案1】:

是的,可以在不超过 (n + log n) 的时间内完成。如果不给出答案,我真的不能告诉你怎么做,但让我试试。 :-)

取 n 个数字,一次成对比较。拿 ceil(n/2) “赢家”,并重复,“像一棵二叉树”。问题:需要多少次比较才能找到最大的比较?这个“赢家”能战胜多少人?第二大可能输给了谁?那么现在需要多少次比较才能找到第二大的数字呢?

结果是总共 n-1 + ceiling(log n) - 1 次比较,其中 log 以 2 为底。您还可以使用对抗性参数证明它在最坏的情况下不可能做得比这更好。

【讨论】:

  • 谢谢。如此简单,却又聪明。现在我将尝试在 Java 中递归高效地对其进行编程......
【解决方案2】:

编辑:糟糕,由于愚蠢而错过了一件简单的事情。该解决方案不正确,尽管我将其保留在这里,因为它仍然是 avg(n+log(n))。感谢 ShreevatsaR 指出我的愚蠢。我确实考虑过树搜索,但完全错过了回溯以找到 log(n) 中第二大数字的想法。

不管怎样,下面我证明了为什么劣质算法不超过 avg(n+log(n))。在现实生活中,它至少应该表现得相当不错。

  • 首先与记录的第二高数字进行比较。
  • 仅当比较成功时,才与记录的最高数字进行比较。

为了证明它是平均 n+log n,我们只需要证明第一次比较平均只成功 log(n) 次。这很容易看到或演示。

  1. 假设 P 为当前第二大数在排序后的列表中的实际位置,并运行算法
  2. 如果 P>2,那么当找到更大的数字时,新的 P 将平均不超过 P/2。
  3. 如果 P=2,则第一次比较不能成功,因为没有大于当前第二大数字的数字。
  4. P 最多可以等于 N
  5. 从 2、3 和 4 可以看出,第一次比较平均不会成功超过 log(N) 次。

【讨论】:

  • 你的第一行是不正确的:在最坏的情况下你不需要 2*n 比较,事实上它可以在 (n-1)+ceiling(log n) 中完成-1,比较,正如问题所要求的那样。我并没有对此表示反对,因为其余的答案是正确的,但实际上,“我想不出办法”并不是证明。 :P
【解决方案3】:

这个怎么样:

for each listOfNumbers as number
    if number > secondHighest
        if number > highest
            secondHighest = highest
            highest = number
        else
            secondHighest = number

【讨论】:

  • 这需要O(2n)比较,大于O(n + log(n))
  • 以上是指最坏情况下的运行时间,如果数字按升序存储。
  • O(2n) 与 O(n) 相同,因此注释没有意义。
  • 是的。循环是单次通过,它将介于 (1 + 2/n) 比较和 2n 之间,具体取决于初始顺序。有更好的主意吗?
  • @Kinopiko,对不起,脑残。忽略O,希望我的评论确实有意义。 (即2n 比较大于n + log(n) 比较)
【解决方案4】:

ShreevatsaR 发布的答案似乎是 O(n log n)。

第一遍(n 次操作)产生 n/2 个答案。通过重复,我猜您的意思是您将执行 n/2 次操作以产生 n/4 个答案。您将浏览循环日志 n 次。这很像归并排序,只是归并排序每次都处理 n 个节点。它还运行循环日志 n 次。而且我看不出这个算法将如何跟踪第二大数字。

nickf 有正确的答案。最坏的情况是当列表被排序时,它将进行 2n 次比较 - 即 O(n)。

顺便说一句,O(n + log n) 是 O(n),Order 表示法是指最坏情况下的渐近增长。

【讨论】:

  • 嗯? n/2 + n/4 + … = n-1。 (另一种理解方式:除了获胜者之外的每个人都输了一次。)我给出的算法恰好进行了 n+log(n)-2 比较(不仅仅是渐近的)。请注意,所讨论的度量是比较次数,而不是运行时间。 (但是 n+log(n) 是 O(n),所以运行时间也是 O(n)。)很抱歉我的答案不太清楚,但我不想完全放弃答案家庭作业问题。
【解决方案5】:

您可以使用计数排序、基数排序、桶排序或其他线性时间算法对列表进行降序排序。然后只需获取排序列表的前 2 个元素。 所以这需要 (n) + 2 = (n)

请注意,此算法可以按线性时间排序,因为每个算法都有自己的假设。

【讨论】:

  • (1) 对于给定的数字没有任何保证,因此线性时间排序是不可能的。 (2) 注意这里的度量是比较的次数,而不是操作的次数 (3) 注意它要求 exactly n+log(n),而不是 O(n + log(n) )) - 这将只是 O(n)。
【解决方案6】:

伪代码(这本质上不是 n 吗?)

int highestNum = 0
int secondHighest = highestNum

for(i = 0; i < list.length; i++)
{
if(list[i] >= highestNum)
{
secondHighest = highestNum
highestNum = list[i]
}
}

【讨论】:

  • 在这个列表上测试:0 3 2 1. secondHighest 将保持为 0。(更一般地说,取任何列表,其中最高数字出现在第二高数字之前,您的代码将错过第二高.)
猜你喜欢
  • 1970-01-01
  • 2013-01-29
  • 2017-07-07
  • 1970-01-01
  • 2010-11-08
  • 2010-11-22
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多