如何仅从文本文件中查找“最小值”和“最大值”进行“ n”次比较?

时间:2019-01-22 04:55:08

标签: java performance

所以我有一个文件,其中包含n个整数。我需要找到一种方法,在找到最小值和最大值而不是2n个比较时进行n个比较。我当前的代码进行了2n次比较...

min=max=infile.nextInt();
while ( infile.hasNextInt() )
    {

        int placeholder = infile.nextInt(); // works as a placeholders
        if (placeholder < min)
        {
            min = placeholder;
        }
        if (placeholder > max)
        {
            max = placeholder;

注意:我只能更改while循环中的内容。我只是不知道如何使用基本的for循环轻松找到最小值和最大值...是否有任何简单的解决方案?我想念什么?

4 个答案:

答案 0 :(得分:2)

我认为您无法在 n 比较中做到这一点。您可以通过 3n / 2-2 进行比较,如下所示:

  1. 成对地取项目并比较每对中的项目。将每个比较的较高值放在一个列表中,将较低值放在另一个列表中。这需要进行 n / 2 个比较。
  2. 从较高值列表中找到最大值: n / 2-1 个比较。
  3. 从较低值列表中找到最小值: n / 2-1 个比较。

答案 1 :(得分:1)

我认为您的方法是最佳的,因为它需要进行 O(n)比较。根据大O n2n不重要:

int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;

while (infile.hasNextInt()) {
    int val = infile.nextInt();

    if(val < min)
        min = val;
    else if(val > max)
        max = val;
}

您可以使用额外的存储空间来做同样的事情,但是在这种情况下,您的比较较少,但是空间却更多:

TreeSet<Integer> unique = new TreeSet<>();

while(infile.hasNextInt())
    unique.add(infile.nextInt());

int min = unique.pollFirst();
int max = unique.pollLast();

答案 2 :(得分:1)

正如MadPhysicist所说:您可以将两个if改为if / else if:

min = max = infile.nextInt();
while (infile.hasNextInt()) {

    int placeholder = infile.nextInt(); // works as a placeholders
    if (placeholder <= min) {
        min = placeholder;
    } else if (placeholder > max) {
        max = placeholder;
    }
}

在最佳情况下(严格递减的序列,每个值均小于前一个值),您只需要进行n-1比较。

在最坏的情况下(严格增加的顺序,每个值都大于前一个值),您仍然需要进行2*(n-1)比较。您无法完全消除这种情况:如果某个值大于当前最小值,则可能是新的最大值。

在典型情况下(值的随机序列),您需要在n-12*(n-1)比较之间进行一些操作。

还要注意,我将最小值的比较从<更改为<=:如果一个值等于最小值,则不能同时是一个新的最大值。

答案 3 :(得分:0)

鉴于您将最小/最大值初始化为第一个元素,因此您有2(n - 1)个比较。此外,如果将两个if更改为if-else if,则将至少保存一个比较,总共为2n - 3

因此可以对@Matt Timmermans' answer进行概括:

将您的输入分成大小为k的组。使用2k - 3比较找出每个组的最大值和最小值。这样就剩下n/k个项目来检查最小值,还有n/k个项目来检查最大值。您有两种选择:

  1. 只需进行比较,总共(n/k) * (2k - 3) + 2 * (n/k - 1)。这表明Matt的答案是最优的,因为表达式对于k = 2来说是最小的(对于k的所有值,分数减小到n之上)。
  2. 继续分成大小为k(或其他大小)的组。要查找最多k个元素,需要进行k-1个比较。因此,您可以将n/k个最低限度的候选人再次划分为k个组,以获得n/k2个候选人,以进行额外的n/k * (k-1)比较。您可以继续执行该过程,总共可以获得(n/k) * (2k - 3) + 2 * (k - 1) * Σ n/ki。总和evaluates to 1 / (k-1),所以总和为> 2n,甚至可以补偿总和中隐含的挥舞过高的逼近度。

方法#2不会减少比较次数的原因是,对于每个标准,将列表分为两组候选者将获得最大的收益。最好通过一次遍历每个列表来优化其余计算。

这个故事的寓意是,尽管您可以在这里和那里保存一些比较,但您可能不应该这样做。除其他因素外,您还必须考虑设置其他列表(甚至进行就地交换)所产生的开销,以及代码易读性降低。