我试图仅使用n + ceil(lg n) - 2
比较来找到n个元素数组中的第二个最小元素。 CLRS中的提示表示要找到最小的元素。
这需要进行n - 1
比较,因此我会在进行ceil(lg n) - 1
比较时找到第二个最小的,一旦我知道最大的。
有什么想法吗?
谢谢,
bclayman
答案 0 :(得分:13)
我们说我们已经列出了 1 ... a n ,其中n
是2的幂。
首先对元素进行配对,让我们说 1 带有 2 , 3 带有 4 等等,并相互比较。这样可以进行n/2
次比较。
将所有获胜者推进到下一轮,现在只有n/2
个元素,并重复相同的过程。这需要进行n/4
次比较。
重复上述步骤,直到你只剩下1个元素,最终获胜者。要实现这一目标,您必须进行n/2 + n/4 + ... + 1 = n-1
比较。
这很棒,但哪一个可能是第二小?好吧,它必须是你的赢家在前往顶峰的过程中击败的元素之一。有lg n
个这样的输家,所以你需要将它们相互比较以找到最小的(需要进一步的lg n - 1
比较)。
最小的输家总体上是第二小的。
很容易证明为什么上述方法总能找到第二小的方法:因为它比每个元素都要小但是最终的胜利者,除了对抗冠军之外,它将赢得每一轮。< / p>
如果n
不是2的幂,则过程几乎完全相同,除了输入列表将与下一次确切的2次幂一样长,这就是为什么你最终得到ceil(lg n)
。
答案 1 :(得分:1)
这是JavaScript中的基本实现,但并不确定它在所有情况下都完全尊重您的O()要求。初始数组也会影响比较计数。
var elements = [ 12, 1 , 3, 4, 65, 7, -43, 8, 3, 8, 45, 2 ];
var nCompare = 0;
var smallest = elements[0], smaller = elements[0];
for(var i = 1; i < elements.length; ++i) {
++nCompare;
if(elements[i] < smaller) {
++nCompare;
if(elements[i] < smallest) {
smaller = smallest;
smallest = elements[i];
}
else
smaller = elements[i];
}
}
document.body.innerHTML = '<pre>\n' +
'Elements: [ ' + elements.join(', ') + ' ]\n' +
'# element: ' + elements.length + '\n' +
'\n' +
'Smallest: ' + smallest + '\n' +
'2nd smallest: ' + smaller + '\n' +
'# compare: ' + nCompare +
'</pre>';
答案 2 :(得分:0)
以下是Java中具有O(n)复杂性的解决方案:
public class MainClass {
public static void main(String[] args) {
int[] a = { 4, 2, 8, -2, 56, 0 };
c(a);
}
private static void c(int[] a) {
int s = Integer.MAX_VALUE;
int ss = Integer.MAX_VALUE;
for (int i : a) {
if (i < s) {
ss = s;
s = i;
} else if (i < ss) {
ss = i;
}
}
System.out.println("smallest : " + s + " second smallest : " + ss);
}
}
输出:最小:-2秒最小值:0
答案 3 :(得分:-1)
我认为他们不需要进行cel(log n)-1的额外比较,因为它只能在O(n)中完成,即在一次扫描中借助于下面给出的额外变量: -
for(i,0,no_of_elem-1)
{
if(min>elem[i])
{
second_smallest=min;
min=elem[i];
}
}
您只需将先前的最小值存储在变量中,因为扫描完所有元素后,这将是您的答案。