【问题标题】:Algorithm complexity算法复杂度
【发布时间】:2017-01-15 21:35:56
【问题描述】:

我遇到了这个问题“实现此方法以返回给定数组中两个最大数字的总和。”

我是这样解决的:

 public static int sumOfTwoLargestElements(int[] a) {

     int firstLargest = largest(a, 0, a.length-1);

     int firstLarge =  a[firstLargest];
     a[firstLargest] = -1;

     int secondLargest = largest(a, 0, a.length-1);

     return firstLarge + a[secondLargest];
}

private static int largest(int s[], int start , int end){

    if (end - start == 0){

        return end;
    }


   int a = largest(s, start, start + (end-start)/2) ;
   int b = largest(s, start + (end-start)/2+1 , end);
    if(s[a] > s[b]) {

       return a;
    }else {

      return b;
    }

}

说明:我实现了一个方法“largeset”。该方法负责获取给定数组中的最大数。

我在同一个数组中调用该方法两次。第一次调用将获得第一个最大的数字。我将它放在变量中,并用“-1”数字替换它到数组中。然后,我第二次调用最大的方法。

有人可以告诉我这个算法的复杂性是什么?请

【问题讨论】:

  • 您可以在第一遍中找到两个数字,并在第二遍中找到。它不会改变复杂性,但它会运行得更快。 :-)
  • +1 表示上述评论。此外,如果它只是一个数字列表,那么还有其他各种解决方法......如果你使用计数排序等机制,额外空间和 O(n) 时间复杂度可以忽略不计......
  • 复杂性的真正衡量标准是未来读者的代码,他们花时间弄清楚它是如何工作的,什么时候更简单的算法可以完成这项工作。递归没有明显的好处,或者为什么需要两次遍历集合。当数组中的两个最大整数都小于 -1 时,该算法从根本上被破坏(返回不正确的结果)。哎呀!

标签: algorithm time-complexity


【解决方案1】:

算法的时间复杂度为O(n)

每个递归调用的复杂度实际上是:

f(n) = 2*f(n/2) + CONST

很容易看出(通过归纳1f(n) <= CONST'*n - 因此它是O(n)

空间复杂度为O(logN)——因为这是递归的最大深度——所以你在调用堆栈上分配O(logN)内存。


(1) 如果你使用f(n) = 2*n*CONST - CONST,你会得到:

f(n) = 2*f(n/2) + CONST = (h.i.) 2*(2*CONST*n/2 - CONST) + CONST =
=  2*n*CONST - 2CONST + CONST = 2*n*CONST - CONST

(检查基数留给读者作为练习)

【讨论】:

  • 那么,f(0) 有负复杂度吗?我宁愿认为复杂度是 O(2^n * log n)。
  • @undur_gongor 显然,该公式不适用于基值或更低值(这是归纳点,我们从某个点开始证明,所有赌注都低于它)。基数应为f(1),如练习所述。
  • @undur_gongor:而且,准确地说——因为我们在证明中只使用了等式,我们实际上证明了f(n)Theta(n) 中——所以O(n) 是一个紧渐近界。
【解决方案2】:

算法的复杂度将被测量为O(n)

但真正的答案是,您的算法比实际需要的要复杂得多,而且在机器资源方面也更加昂贵。就有人阅读您的代码并弄清楚它在做什么而言,它的成本要高得多。

算法的复杂度实际上应该是:

public static int sumOfTwoLargestElements(int[] a) {

    //TODO handle case when argument is null,
    //TODO handle case when array has less than two non-null elements, etc.

    int firstLargest = Integer.MIN_VALUE;
    int secondLargest = Integer.MIN_VALUE;
    for (int v : a) {
        if ( v > firstLargest ) {
            secondLargest = firstLargest;
            firstLargest = v;
        } else if ( v > secondLargest ) secondLargest = v;
    }
    //TODO handle case when sum exceeds Integer.MAX_VALUE;
    return firstLargest + secondLargest;
}

【讨论】:

  • 我想你需要if ( v > firstLargest ) { secondLargest = firstLargest; firstLargest = v };
【解决方案3】:

“最大”方法的递归是:

        _
f(n) = !
       !  1        n = 1
       !  2f(n/2)  n >=2 
       !_

If we experiment some few cases, we notice that 

f(n) = 2^log(n)   When n is power of 2       Rq:Log base 2

Proof:

By induction,

f(1) = 2^log(1) = 2^log(2^0) = 1

We suppose that f(n) = 2^log(n)=n

We show f(2n) = 2^log(2n)= 2n^log(2)=2n

f(2n) = 2*f(2n/2) = 2*f(n)
                  = 2*2^log(n)
                  = 2^log(n) + 1
                  = 2^log(n) + log(2^0)
                  = 2^log(2n)
                  = 2n^log(2)  by log properties
                  = 2n
Then f(n) = 2^log(n)=n  When n is power of2-smooth function f(2n) < c f(n). it follows smooth function properties that **f(n) = theta of n**

【讨论】:

    猜你喜欢
    • 2021-04-22
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-12
    • 2011-06-21
    • 2012-05-09
    • 2017-06-13
    相关资源
    最近更新 更多