【问题标题】:Simple "maximum value in array" and complexity calculations简单的“数组中的最大值”和复杂度计算
【发布时间】:2012-11-03 00:29:45
【问题描述】:

我对这些东西很陌生,我需要你的帮助。

我应该构建一个高效的简单算法,它返回一个大小为 n 的数组中的最大值,该数组包含重复的数字 1,2,...n。

然后我要确定最佳运行时间、平均运行时间和最差运行时间。

所以我有两个问题:

  1. 首先,我试图理解为这个简单的算法需要一个有效解决方案的想法是什么。据我了解,我应该只有一个从 1 到 n 的简单循环并寻找最大值。 “高效”算法是否指出如果我在数组中找到值 n,我可以停止搜索更多值,因为这是数组中的最大值?

  2. 如何确定最佳运行时间和平均运行时间,同时计算平均运行时间,这是一个均匀分布。 也就是说,数组中的每个单元格都有 1/n 的机会成为最大值。

提前非常感谢!

【问题讨论】:

  • 听起来像是功课……到目前为止,你有什么想法?提示:排序数组的最大/最小值的运行时间为 O(1)。
  • @MarcB:但是确定数组是否排序是 O(n) :|
  • 所以只是在任意数组上提取最大值/最小值。
  • @MarcB 数组未排序。我不需要解决方案,而是需要对具体答案的一些解释。至于我到目前为止提出的问题,我在我的问题中写道。
  • “一个数组中的最大值,大小为n,其中包含数字1,2,...n,重复”显然是n,不是吗?

标签: algorithm complexity-theory


【解决方案1】:

最好的情况 - 找到最大元素作为第一个 (O(1)),最坏的情况 - 它是检查的最后一个元素 (O(n))。

棘手的部分是平均情况。
要找到平均情况 - 我们需要 expected 的迭代次数!

既然找到最大值就可以停下来,我们可以把问题分成两部分:

  1. [0,n-1):因为平均而言(假设每个元素均匀独立分布) - 数字n 在每个位置的概率为 1/n,那么这部分的预期迭代次数为 1/n + 2*((n-1)/n)/n + 3 * ((n-1)/n)^2/n + ... + (n-1) * ((n-1)/n)^(n-2)/n 1
    The above formula yields an ugly formula which is O(n)
  2. 如果前n-1个元素不包含值n,则将检查最后一个元素:因此您需要添加到上面的n* ((n-1)/n)^(n-1),也就是O(n)(限制到无穷大是1/e * n)。

这总计在O(n) 平均时间解决方案中。


(1):每个元素的公式是j*((n-1)/n)^(j-1) * (1/n),因为:

  • j - 检查元素的数量(迭代次数)
  • ((n-1)/n)^(j-1) - 前面的元素中没有 n 的概率
  • (1/n) - 这个数字的概率是n

【讨论】:

  • 哇@amit 我无话可说。说得真好。真的很感激。
  • “有重复”位表示它不是随机排列。仅在1..n 范围内的 n 个随机整数。
  • @btilly:术语排列是错误的,但请注意,计算没有假设排列 - 它假设每个元素的均匀分布 - 所以它(每个元素)有 1/n 机会成为最大值和(n-1)/n 不是这样。我会更正术语。感谢您的评论。
  • 为什么最好的情况是 O(1)?在不知道数组其余部分的内容的情况下,您无法确定数组的任何一个元素都是最大值...
  • @William 请注意,问题指出数组 contains the numbers 1,2,...n with repetitions。最好的情况实际上是:读取第一个元素,看到它是 n,然后返回它。这是 O(1)。
【解决方案2】:

如果没有关于数组的先验信息(例如它已排序),则没有最坏情况或最佳情况,您必须扫描所有元素以找出最大值,并且需要 O(n) 次.

此外,知道每个单元格获得最大值的概率分布通常是没有用的(除非它减少了您的搜索空间。例如,如果您知道只有恒定数量的单元格获得最大值的概率非零,那么你只需要搜索这些单元格并且它需要恒定的时间)。因此,总的来说

最佳情况运行时间 = 最坏情况运行时间 = 平均运行时间 = O(n)

【讨论】:

    【解决方案3】:

    算法是这样工作的,首先你选择一个数字(在这种情况下,我选择数组的第一个数字并假装它是最大值,然后我将它与下一个数字进行比较,如果它更大,我将其视为新的最大值,直到我在数组中完成搜索),下一个代码在 C 中:

    #include <stdio.h>
    #define SIZE 100
    
    typedef struct{
        int val;
        int loc;
    } find;
    
    /* Functions declaration (Prototype) */
    find maxFinder( int * const a );
    
    int main( void )
    {
        int response[ SIZE ]=
           { 1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100,
             1, 3, 5, 7,  8, 9, 0, 10, 65, 100 };
    
        printf( "The max number is %d located in the index %d.\n", maxFinder( response ).val, maxFinder( response ).loc );
        return 0;
    }
    
     find maxFinder( int * const a )
     {
        /* Local Variables initialization & declaration */
        int i;
        find result;
    
        result.loc = 0;
        result.val = *( a + 0 );
    
        for( i = 1; i < SIZE; i++ ){
            if ( result.val < *( a + i ) ){
                result.loc = i;
                result.val = *( a + i );
            }
        }
        return result;
     }
    

    【讨论】:

    • 您不应该使用数字介于 1... SIZE 之间的事实吗?
    • SIZE 是一个必须声明的常量值,在我的例子中是 100。
    • 在这种情况下 SIZE = n 并且您的值介于 1...n 之间。这不是您所展示的一般情况。
    • 一般情况下,根据需要改变SIZE值,从0(数组的第一个元素直到数组完成(n-1))开始搜索
    • @Alberto Bonsanto:你能分享一下 Javascript / PHP 的代码吗?请
    【解决方案4】:

    最坏和最好的情况都很简单。平均情况更有趣。查看Geometric Distribution 的维基百科页面。

    【讨论】:

    • 最好的情况 - 如果它是第一个元素:O(1) 和最坏的情况:O(n),对吗?
    • 根据您的 cmets,您似乎很自信并且理解这个想法。跟着你的直觉走:)
    猜你喜欢
    • 1970-01-01
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多