有一天我被问到写一个基本的方法,当给予两个朋友时,如果他们被联系(我的意思是他们是朋友的朋友的朋友),他们会返回true,如果他们是无关(他们的朋友列表中没有人连接)。
在与这个人合作之后,这是我们的基本算法:
def is_linked(friend_a, friend_b, visited = {}):
is_found = False
friends = friend_a.get_friends()
# You can assume this method is O(1)
if friends.contains(friend_b):
return True
visited[friend_a] = 1
for friend in friends:
# Prevents infinite recursion
# Assume O(1)
if friend in visited:
next
is_found = is_linked(friend, friend_b, visited)
if is_found:
last
del visited[friend_a]
return is_found
这个算法的最坏情况时间复杂度是多少?我们每个人都提出了自己的答案,因为我们无法达成协议,我希望能在这里独立验证。< / p>
答案 0 :(得分:2)
我要把答案扔出去。我认为维基百科上的Breadth-first search文章涵盖了它,它表明它实际上取决于边E
和节N
的数量,并且具有不同的最佳和最差情况值。带有关键区域的代码已注释
def is_linked(friend_a, friend_b, visited = {}): # At worst, will call this N-1 times
friends = friend_a.get_friends()
# You can assume this method is O(1)
if friends.contains(friend_b):
return True
visited[friend_a] = 1
for friend in friends:
# Prevents infinite recursion
# Assume O(1)
if friend in visited:
next # At worst, this will happen N-2 times
return is_linked(friend, friend_b, visited)
del visited[friend_a]
return False
绝对最坏的情况? O((N-1)(N-2))
这是O(N^2)
。如果您可以说您的图表连接稀疏,则可以达到O(N)
,因为if friend in visited: next
很少会发生。
答案 1 :(得分:1)
如果if friend in visited
和friends.contains
都是O(1),那么整个函数必须是O(n);如果对is_linked
的单个调用(假设没有递归)在恒定时间内完成(因为它必须在它所做的一切都在恒定时间内完成),那么带递归的调用的完成时间与递归的数量呈线性关系发生,即必须检查以找到链接的朋友的数量。我没有能力提供这方面的数学证明,但请考虑:
a[friends] = [c, d, e]
b[friends] = [e, f, g]
[...]
e[friends] = [a, b]
在这种情况下,调用is_linked(a, b)
将导致总共四次调用:
is_linked(a,b)#原始呼叫 is_linked(c,b,{a:1}) is_linked(d,b,{a:1,c:1}) is_linked(e,b,{a:1,c:1,d:1})#True
类似地:
a[friends] = [b, c]
b[friends] = [c, d]
c[friends] = [d, e]
d[friends] = [e]
调用is_linked(a, e)
也会导致四次调用:
is_linked(a, e) # original call
is_linked(b, e, {a: 1})
is_linked(c, e, {a: 1, b: 1})
is_linked(d, e, {a: 1, b: 1, c: 1}) # True
同时
a[friends] = [b, c, d, e, f, g]
[...]
g[friends] = []
is_linked(a, g)
导致六次通话,&amp; c。所有这一切的目的是证明,如果不是为了证明,is_linked
所花费的时间与它必须检查的项目数量呈线性关系。
我不是立即熟悉Python的字典键查找实现(if friend in visited
);一个简单的实现,作为跨密钥数组的线性搜索,将具有复杂度O(n),导致我最初为is_linked
假设的O(n ^ 2)复杂度。但是,根据this,他们已经将其归结为“O(1)的平均复杂度”。如果这是真的,那么is_linked
确实是O(n);如果,我怀疑可能是这种情况,实际上它更接近于O(log n),那么is_linked
应该是O(n log n),这仍然不是那么糟糕。
更新:dlp指出for friend in friends
中存在数组遍历(is_linked
),以及密钥查找。该迭代总是为O(n),这将使is_linked
至少必须为O(n ^ 2)。 (可以是O(n ^ 2 log n)吗?家里有计算机科学家吗?我的意思是,我不是一个......)