在给定集合中查找最小值和最大值的算法

时间:2013-05-04 07:56:34

标签: c++ algorithm

给出一个大数组array[n]的整数作为输入。给出了两个索引值 - start,end。希望快速找到 - min & max in the set [start,end](包括)和max in the rest of array(不包括[start,end])。

例如 -

阵列 - 3 4 2 2 1 3 12 5 7 9 7 10 1 5 2 3 1 1

开始,结束 - 2,7

min,最大值[2,7] - 1,12

最多休息 - 10

我想不出比线性更好的东西。但是这不够好n is of order 10^5,并且此类查找操作的数量也是相同的顺序。

任何帮助都将受到高度赞赏。

8 个答案:

答案 0 :(得分:6)

我理解你的问题的方法是你想在固定数组上做一些预处理,然后让你的find max操作非常快。

这个答案描述了一种方法,它执行O(nlogn)预处理工作,然后为每个查询执行O(1)工作。

预处理O(nlogn)

想法是准备两个2d阵列BIG [a,k]和SMALL [a,k]其中

1. BIG[a,k] is the max of the 2^k elements starting at a
2. SMALL[a,k] is the min of the 2^k elements starting at a

您可以通过从k == 0开始以递归方式计算此数组,然后通过将前两个元素组合在一起来为每个更高元素构建值。

BIG[a,k] = max(BIG[a,k-1] , BIG[a+2^(k-1),k-1])
SMALL[a,k] = min(SMALL[a,k-1] , SMALL[a+2^(k-1),k-1])

每个查询查找O(1)

然后,您可以通过组合2个准备好的答案立即找到任何范围的最大值和最小值。

假设您要查找从100到133的元素的最大值。 你已经知道最多32个元素100到131(在BIG [100,5]中)以及最多32个元素从102到133(在BIG [102,5]中)所以你可以找到最大的这些元素得到答案。

同样的逻辑适用于最小值。您总能找到两个重叠的准备好的答案,这些答案将结合起来提供您需要的答案。

答案 1 :(得分:3)

我担心,没有更快的方法。您的数据是完全随机的,这样,您必须遍历每个值。 即使排序也不会帮助你,因为它最好是O(n log n),所以它的速度较慢。您不能使用二分法,因为数据未排序。如果你开始构建数据结构(比如堆),它将再次成为O(n log n)。

答案 2 :(得分:3)

您要求的数据结构将快速回答阵列上的间隔的最小和最大查询。

您想在输入数组上构建两个segment trees;一个用于回答间隔最小查询,一个用于回答间隔最大查询。这需要线性预处理,线性额外空间,并允许查询采用对数时间。

答案 3 :(得分:2)

如果数组非常大,则将其拆分为分区并使用线程对每个分区进行线性检查。然后使用线程的结果执行min / max。

答案 4 :(得分:1)

在未排序的数组中搜索最小值和最大值只能通过一次取两个值并首先将它们相互比较来优化:

register int min, max, i;
min = max = array[0] ;

for(i = 1; i + 1 < length; i += 2)
{
    if(array[i] < array[i+1])
    {
        if(min > array[i]) min = array[i];
        if(max < array[i+1]) max = array[i+1];
    }
    else
    {
        if(min > array[i+1]) min = array[i];
        if(max < array[i]) max = array[i+1];
    }
}

if(i < length)
    if(min > array[i]) min = array[i];
    else if(max < array[i]) max = array[i];

但我不相信它实际上更快。考虑将它写在汇编中。

编辑: 比较字符串时,此算法可能有所作为!

答案 5 :(得分:0)

如果您知道min,如果数组中存在该值,则可以从x到min进行测试。如果你知道最大值,你可以测试(向后)从y到最大值,如果值存在于数组中,你会发现最大值。

例如,从你的数组中,我假设你只有正整数。:

array - 3 4 2 2 1 3 12 5 7 9 7 10 1 5 2 3 1 1

你将x设置为0,测试0是否存在,不是,然后你将它改为1,你找到1.你的分钟。 你将y设置为15(任意大数):存在?没有。设置为14.存在吗?不,设置为13.存在吗?没有。设为12.存在吗?是!有你的最大值!我只做了4次比较。

如果第一次尝试中存在y,则可能已在数组中测试了一个值。所以你用y + length / 2再次测试它。假设你找到了数组的中心,所以给它贴了一点。如果再次找到第一次尝试的值,它可能在数组中。

如果您有负值和/或浮点值,则此方法不起作用:)

答案 6 :(得分:0)

当然,不可能使用子线性算法(据我所知)来搜索你想要的方式。但是,在某些情况下,您可以通过存储min-max的固定范围来实现亚线性时间,并且通过一些范围的知识可以缩短搜索时间。 例如如果你知道搜索的“大部分”时间范围是10,那么你可以分别存储10/2 = 5个元素的最小 - 最大值并索引这些范围。在搜索过程中,您必须找到可以包含搜索范围的范围的超集。

e.g。在示例中 阵列 - 3 4 2 2 1 3 12 5 7 9 7 10 1 5 2 3 1 1

开始,结束 - 2,7

min,最大值[2,7] - 1,12

如果您“知道”大部分时间搜索范围将是5个元素,那么您可以事先索引min-max,如:自5/2 = 2,

0-1  min-max (3,4)
2-3  min-max (2,2)
4-5  min-max (1,3)
6-7  min-max (5,12)
...

我认为,当范围很大时,这种方法会更好,因此存储min-max可以避免一些搜索。

要搜索min-max [2-7],您必须搜索存储的索引,例如:2/2 = 1到7/2 = 3, 然后最小分钟(2,1,5)将给你最小(1)和最大最大(2,3,12)将给你最大(12)。如果出现重叠,则必须仅搜索角点索引(线性)。我认为它仍然可以避免几次搜索。

这种算法可能比线性搜索慢(因为线性搜索具有非常好的参考局部性),所以我建议你先测量它们。

答案 7 :(得分:-1)

线性是你能做的最好的,它相对容易证明它。

假设无限量的瞬时内存存储和无成本访问,我们可以忽略它们。

此外,我们将假设你在子字符串中找到min / max的任务。我们将它们视为完全相同的机械问题。在比较中,人们只是神奇地跟踪比其他数字更小的数字,并且可以神奇地跟踪比对比中更大的数字。假设这一行动是无成本的。

然后让我们假设子阵列问题的最小值/最大值,因为它与任何数组的最小值/最大值有同样的问题,我们会神奇地认为它已经解决并作为我们一般行动的一部分在更大的数组中找到最大值。我们可以通过假设整个数组中的最大数字实际上是我们看到的第一个数字来实现这一点,它也是一个神奇的侥幸,它也是子数组中最大的数字,也恰好是最小的数字。子阵列,但我们不知道我们有多幸运。我们怎么知道?

我们要做的最少的工作是将它与数组中的每个其他数字进行比较,以证明它是最大/最小的。这是我们假设有成本的唯一行动。

我们需要进行多少次比较?我们将N设为数组的长度,并且任何长度N的操作总数为N-1。当我们向数组添加元素时,即使我们所有广泛的比较,比较的数量也会以相同的速率扩展令人愤慨的假设是正确的。

所以我们已经到了N是数组长度的点,以及在我们极不切实际的最佳情况下最佳可能操作成本增加的决定因素。

在最佳情况下,您的操作会按N缩放。对不起。

/对输入进行排序必须比这个最小操作更昂贵,所以它只适用于你多次进行操作,并且无法存储实际结果的情况,这似乎不太可能,因为10 ^ 5答案并不完全是税收。

//多线程等等一切都很好,只是假设没有这样做的成本,并将N除以线程数。然而,最好的算法仍然可以线性扩展。

///我猜它实际上必须是一个特别奇怪的现象,任何事物都要比线性地扩展得更好而不假设有关数据的东西... stackoverflowers?

相关问题