这是我必须回答的面试问题。实际上是朋友,但他问我,我也不知道答案。因此,我在这里问:
给定8个整数的数组,仅使用9个比较找到最小和第二个最小整数。更具体地说,在n+log(n)-2
时间。
我要注意如何只使用9次比较来完成它。这就是我接近它的原因。 (10次比较)
public class Comp {
static int[] nums = new int[]{9, 4, 5, 3, 2, 7, 6, 1};
static int compcount = 0;
//int[] is nums[] array
public static int[] twoLeast(int[] a){
int min1 = a[0]; //Prospective lowest number
int min2 = a[1]; //Prospective second lowest number
if(isLessThan(min2, min1)){
min1 = a[1];
min2 = a[0];
}
for(int i=2; i<a.length;i++){
if(isLessThan(a[i], min1)){
min2 = min1;
min1 = a[i];
}else if(isLessThan(a[i], min2)){
min2 = a[i];
}
}
return new int[]{min1, min2};
}
public static boolean isLessThan(int num1, int num2){
compcount++;
return num1 < num2;
}
}
这里我有一个函数isLessThan()
来跟踪比较次数。
再次,这进行了10次比较。如何在9次比较中做到这一点。或者在n+log(n)-2
时间?
P.S:我在java中实现了它,但它可以是任何语言
答案 0 :(得分:9)
考虑解决方案的一种方式是,这就像网球淘汰赛系列。假设每个数字对应一个玩家。配对数字,让每个游戏对应一对数字之间的比较:
游戏:(a1,a2)
,(a3, a4)
,(a5, a6)
,(a7, a8)
获奖者:a12
,a34
,a56
,a78
游戏:(a12, a34)
,(a56, a78)
获奖者:a1234
,a5678
游戏:(a1234, a5678)
获奖者:a12345678
游戏数量= 7
==&gt; (n - 1)
第二好的只会被胜利者击败。假设a3
是赢家。然后,第二好的将是a4
,a12
或a5678
。
游戏:(a4, a12)
获奖者:a412
游戏:a(412, 5678)
获奖者:a4125678
所以我们有2
场比赛的第二好的==&gt; (lg(n) - 1)
因此游戏数量= 7 + 2 = 9
= (n + lg(n) - 2)
这样可以更容易地将上述比赛视为一棵树:
a12345678
/ \
/ \
/ \
/ \
a1234 a5678
/ \ / \
/ \ / \
a12 a34 a56 a78
/ \ / \ / \ / \
a1 a2 a3 a4 a5 a6 a7 a8
如果a3
是赢家,我们有:
a3
|
/----|----\
/ \
/ \
/ \
a3 >==========> a5678
/ \ / \
/ \ / \
a12 <====< a3 a56 a78
/ \ / \ / \ / \
a1 a2 a3 ->a4 a5 a6 a7 a8
基本上,最终的胜利者a3
将遍历从叶子到根(lg(n) -1
)的路径。在他的道路上,他将击败第二好的球员,这是{a4, a12, a5678}
之一。因此,我们可以通过查看除了胜利者之外的路径中的最大值来确定谁是第二好的。
答案 1 :(得分:6)
作为提示,为阵列的元素设置淘汰锦标赛支架。阵列中最大的数字将赢得比赛,如果n是a,你只需要n - 1比较两个人的力量。
第二大元素必须只丢失到最大元素,而在锦标赛中,最大元素只能击败其他元素。只发布那些元素的第二次淘汰赛,找到那里最大的元素,这需要log n - 1比较。
总的来说,只需要n + log n - 2次总比较。剩下的就是编码了。
希望这有帮助!