是否可以使用单次传递获得列表中的2个最大数字?

时间:2011-10-18 14:33:42

标签: c# algorithm max

是否有可能在数组中找到2个最大的数字,并且只能遍历集合一次?

我把这作为面试问题并没有及时得到它。

3 个答案:

答案 0 :(得分:29)

看起来很简单..

int[] nums = { 3, 1, 4, 1, 5, 9, 2, 6 };

int max1 = -1;
int max2 = -1;
foreach (int num in nums)
{
  if (num > max1) { max2 = max1; max1 = num; }
  else if (num > max2) { max2 = num; }
}    

例如:

// 3: max2 = -1; max1 = 3;
// 1: max2 = 1;
// 4: max2 = 3; max1 = 4;

快速解释:

  • 将-1定义为占位符,可以使用int.MinValue,或者更好的是单独的bool来表示不匹配
  • 如果测试的值大于当前最大值(max1),则将当前最大值分配给max2,将新值分配给max1
  • 否则如果必须更小,但如果它大于第二个最大值,则为max2分配新值

答案 1 :(得分:1)

通常,对于任何K,您可以使用单次传递找到数组中的K个最大(或最小)数字。总时间复杂度将为O(NK),其中N是数组的大小:

保留一个最多包含K个元素的数字排序列表。遍历数组和每个项目:

  1. 如果列表尚未填满,请插入项目
  2. 否则,如果项目大于列表中的最小项目,请插入此项目并删除最小项目。
  3. 最后,列表将包含K个最大的项目,这就是我们想要的。

    但这个解决方案很慢。使用自平衡二叉搜索树或跳过列表,您可以达到O(N log K)。 (因为在一般情况下不可能比O(N log N)更快地排序,并且如果我们设置K = N,这个方法可以用于对整个数组进行排序,这看起来是我们能得到的最好的。)

    在K = 2的情况下,您不需要所有这些重型机械。表示列表中两个位置的两个变量就足够了。

答案 2 :(得分:0)

是的,确实如此。在遍历列表时,记录找到的最大数字,每当找到更大的数字时,在找到最大的数字之前,将找到的最大数字保存到第二大。如果该值大于第二大值,则更新第二大值。