我的代码的时间复杂度是log(n)吗?

时间:2013-11-20 15:11:50

标签: python algorithm recursion complexity-theory time-complexity

方法foo将带有不同数字的排序列表作为参数,并返回所有出现次数的计数:i == list[i](其中i是索引0 <= i <= len(list))。

def foo_helper(lst, start, end):

    if start > end:
        # end of recursion
        return 0

    if lst[end] < end or lst[start] > start:
        # no point checking this part of the list
        return 0

    # all indexes must be equal to their values
    if abs(end - start) == lst[end] - lst[start]:
        return end - start + 1

    middle = (end + start) // 2

    print(lst[start:end+1], start, middle, end)

    if lst[middle] == middle:
        #print("lst[" , middle , "]=", lst[middle])
        return 1 + foo_helper(lst, middle+1, end) + foo_helper(lst, start, middle-1)


    elif lst[middle] < middle:
        return foo_helper(lst, middle+1, end)
    else:
        return foo_helper(lst, start, middle-1)

def foo(lst):
    return foo_helper(lst, 0, len(lst)-1)

我的问题是这段代码的最坏情况复杂性 = log(n)?
如果没有,我应该做些什么?

2 个答案:

答案 0 :(得分:2)

如果您有一个N个数字的列表,这些数字都是唯一的,并且已知有待排序,那么如果list[0] == 0list[N-1] == N-1,则唯一性和排序属性会指示整个列表符合list[i] == i的财产。这可以在O(1)时间确定 - 只需检查第一个和最后一个列表条目。

唯一性和排序属性强制任何列表具有三个单独的区域 - 可能为空的前缀区域list[i] < i,可能为空的中间区域list[i] == i,以及可能为空的后缀区域,其中list[i] > i] 1}}。在一般情况下,找到中间区域需要O(n)时间 - 从前面扫描以找到list[i] == i的第一个索引,并从后面扫描以找到最后一个这样的索引(或者你可以用一次正向扫描做两件事。一旦找到了这些,就可以通过唯一性和顺序来保证,它们之间的所有索引都具有相同的属性......

编辑:正如下面@tobias_k所指出的那样,你也可以进行二分搜索,找到两个终点,即O(log n)而不是O(n)。如果您的输入完全一般,这将是更好的选择。

答案 1 :(得分:2)

扩展我的评论,试图考虑这个问题。考虑身份函数的图表,它代表索引。我们想知道这个排序列表(严格单调函数)与表示索引y = x的线相交的位置,仅考虑整数位置。我认为你应该能够在O(n)时间内找到它(正如所评论的那样,似乎二元搜索交叉边界应该有效),尽管我需要更仔细地查看你的代码以了解它正在做什么。

因为我们有一个包含唯一元素的排序列表,所以我们在任何地方都有i == list[i]

enter image description here

在一个地方

enter image description here

或者如果有多个地方,他们必须是连续的(一旦你在线以上就永远不能回来)

enter image description here

使用的代码:

import numpy as np
import matplotlib.pyplot as plt
a = np.unique(np.random.randint(-25, 50, 50))
indices = range(len(a))
plt.scatter(indices, indices, c='b')
plt.scatter(indices, a, c='r')
plt.show()