给定n个数字,我如何找到最多使用n + log(n)比较的最大和第二大数字?
请注意,它不是O(n + log(n)),而是n + log(n)比较。
答案 0 :(得分:11)
让我详细说明。
正如帕伊顿所说,这可以通过比赛选择来完成。
将此视为一场淘汰单打网球锦标赛,其中球员的能力有严格的顺序,而比赛的结果完全取决于该顺序。
在第一轮比赛中,一半人被淘汰出局。在下一轮另一半等(可能有一些脚本)。
最终赢家将在最后一轮和最后一轮决定。
这可以看作是一棵树。
树的每个节点都将成为该节点子节点之间匹配的赢家。
树叶是球员。第一轮的胜利者是叶子的父母等。
这是n个节点上的完整二叉树。
现在按照胜利者的路径行事。赢家已经进行了log n匹配。现在考虑那些log n匹配的输家。其中第二好的必须是最好的。
获胜者以n-1场比赛决定(你每场比赛淘汰一场),而logn中的获胜者将以logn -1比赛决定。
因此,你可以决定n + logn中最大和第二大的比较。
事实上,它可以证明这是最佳的。在最坏情况下的任何比较方案中,获胜者必须参加登录比赛。
为了证明假设一个点系统,在一场比赛之后,获胜者获得了输家的分数。最初都是从每个1点开始。
最后的胜利者有n分。
现在给出任何算法,它可以安排,以便有更多积分的玩家永远是赢家。由于任何人的得分在该场景中的任何比赛中最多为两倍,因此在最坏的情况下至少需要获胜者所玩的log n匹配。
答案 1 :(得分:1)
这有问题吗?最多3n次比较(不计算i < n
比较)。如果算上这个,那就是4n(或者在第二个例子中是5n)。
double first = -1e300, second = -1e300;
for (i = 0; i < n; i++){
if (a[i] > first){
second = first;
first = a[i];
}
else if (a[i] > second && a[i] < first){
second = a[i];
}
}
另一种编码方式:
for (i = 0; i < n; i++) if (a[i] > first) first = a[i];
for (i = 0; i < n; i++) if (a[i] < first && a[i] > second) second = a[i];