所以我有一个文件,其中包含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循环轻松找到最小值和最大值...是否有任何简单的解决方案?我想念什么?
答案 0 :(得分:2)
我认为您无法在 n 比较中做到这一点。您可以通过 3n / 2-2 进行比较,如下所示:
答案 1 :(得分:1)
我认为您的方法是最佳的,因为它需要进行 O(n)比较。根据大O ,n
或2n
不重要:
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-1
和2*(n-1)
比较之间进行一些操作。
还要注意,我将最小值的比较从<
更改为<=
:如果一个值等于最小值,则不能同时是一个新的最大值。
答案 3 :(得分:0)
鉴于您将最小/最大值初始化为第一个元素,因此您有2(n - 1)
个比较。此外,如果将两个if
更改为if-else if
,则将至少保存一个比较,总共为2n - 3
。
因此可以对@Matt Timmermans' answer进行概括:
将您的输入分成大小为k
的组。使用2k - 3
比较找出每个组的最大值和最小值。这样就剩下n/k
个项目来检查最小值,还有n/k
个项目来检查最大值。您有两种选择:
(n/k) * (2k - 3) + 2 * (n/k - 1)
。这表明Matt的答案是最优的,因为表达式对于k = 2
来说是最小的(对于k
的所有值,分数减小到n
之上)。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不会减少比较次数的原因是,对于每个标准,将列表分为两组候选者将获得最大的收益。最好通过一次遍历每个列表来优化其余计算。
这个故事的寓意是,尽管您可以在这里和那里保存一些比较,但您可能不应该这样做。除其他因素外,您还必须考虑设置其他列表(甚至进行就地交换)所产生的开销,以及代码易读性降低。