【问题标题】:Proof time complexity for recursive function递归函数的证明时间复杂度
【发布时间】:2014-03-26 15:33:06
【问题描述】:

我正在尝试确定此函数的复杂性,其中 D 和 element 是整数,而 list 是整数的有序列表。请注意, (otherElement-element) 将严格为正。

def doFunc(element, D, list):
  x = 0 
  if(D > 0):
    for otherElement in list:
      if otherElement == element:
        x += 1
      if otherElement > element:
        return x + (doFunc (otherElement,D-(otherElement-element) , list))
  return x

鉴于列表不会总是完全迭代,我不知道如何确定此函数的时间复杂度。

【问题讨论】:

  • 参见stackoverflow.com/a/22615862/847269,我在其中回答了一个与此类似但明显不同的问题。
  • 我尝试优化算法。你看,我必须以严格低于 O(n^2) 的时间复杂度来解决问题,但我并没有真正了解如何计算大 o。我虽然添加一个新条件可能会帮助我降低复杂性。你是说它和我之前发布的一样吗?
  • 否;我现在正在写一个答案,但这里的复杂性确实更好。只是指出这是一个类似的问题;对不起,如果这是你的问题,我不认识你:)
  • 没问题,谢谢帮助

标签: big-o time-complexity proof


【解决方案1】:

doFunc 从左到右检查list 以找到大于或等于提供的elementotherElement。最多进行一次递归调用。我们可以通过推断必须是最坏情况的输入并分析行为来尝试找出该函数的最坏情况时间复杂度。

假设我们从一个大小为 1 的列表开始;称之为{1}。如果我们调用这个列表中的函数,我们可能从for 循环中得到最多的迭代是多少?好吧,如果我们设置element = 1,我们会得到一次迭代。但是,如果设置element = 0,我们可以让doFuncelement = 1递归调用自己;这意味着我们得到了两次迭代。说服自己,对于这个列表,我们永远无法从doFunc 中获得超过两次的迭代。还要说服自己{1} 的选择本质上并不重要;任何单元素列表都将以相同的方式工作。

现在假设我们想要找到一个长度为 2 的最坏情况列表;下一个数字应该相同、更大还是更小?考虑{1, 1}{1, 2}{1, 0}。用element = -1 调用doFunc 将分别导致for 循环的最多3、5 和3 次迭代。添加更大的元素会导致长度为 2 的列表的最坏行为。

说服自己最坏的情况是数字的升序列表;实际上,由于D 的限制因素,最坏的情况是n 元素的{a, a+1, a+2, ..., a+n-1} 形式的列表。对于这样的列表,我们在设置element < a时有以下行为:

  1. doFunc 的初始调用进行一次迭代;然后我们有otherElement > element,所以我们递归调用doFunc
  2. doFunc的第一次递归调用的两次迭代;然后我们有otherElement > element,所以我们再次递归调用。
  3. 同样,在kth 递归调用doFunc 时,我们应该期望for 循环的k+1 迭代。由于for 循环在单个调用的上下文中不能迭代超过n 次,这意味着我们最多有n - 1 递归调用doFunc

我们有1 + 2 + ... + n = O(n^2)。这是假设d > n。假设d < n,我们不能得到所有的递归调用;在这种情况下,我们最多可以有1 + 2 + ... + d 迭代,或者O(d^2)。因此,此函数的最坏情况行为是O(min(n^2, d^2))。你另一个问题的复杂度是O(dn),比这里的复杂度差,除非d = n,在这种情况下性能是一样的。

编辑:另请注意,这里的时间复杂度常数几乎可以保证明显优于其他尝试,因此尽管具有相同的渐近复杂度,但您会看到明显更好的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-29
    • 2018-08-18
    • 1970-01-01
    相关资源
    最近更新 更多