练习邻接表和BFS的编码练习

问题描述

我有一对蹦床的编码练习,每个蹦床都有最小和最大的“蹦蹦跳跳”。我有一个起始蹦床和一个终点蹦床的索引,因此,我需要找到从起始蹦床到达终点蹦床所需的最小跳跃量。

我尝试创建一个邻接表,在其中列出了蹦床可能发生的所有跳跃。直到我到达大量蹦床之前,这很好。问题在于它需要O(n ^ 2)时间。 这是创建邻接表的方法

def createal (a,b,l):
al = [list() for _ in range(l)]
for i in range(l):
    
    for j in range(a[i],b[i]+1):
        if (i+j) <= l-1:
            al[i].append(i+j)
        if (i-j) >= 0:
            al[i].append(i-j)


for i in range(len(al)):
    al[i] = list(set(al[i]))

return al

“ a”是最小值。跳动,“ b”表示最大跳动,“ l”表示两个列表的长度。

如您所见,问题是我有2个嵌套循环。有谁想出一种更有效的方法吗? (最好是wo /循环)

解决方法

假设“弹跳性”严格意义上是肯定的,则可以省略此部分:

for i in range(len(al)):
    al[i] = list(set(al[i]))

...因为您不可能在这些列表中有重复项。

(但是,如果蹦蹦跳跳可能是0或负数,则首先在a中将小于1的值替换为1)

可以通过以下方法使a的构建更快一些:

  • 在实际目标索引上确定范围(因此您不需要在每个循环中使用i+j
  • 使用min()max()限制这些范围,避免在循环中使用if条语句
  • 使用列表理解功能避免单独的append通话

结果:

al = [
    [*range(max(0,i-b[i]),i-a[i]+1),*range(i+a[i],min(l,i+b[i]+1))]
        for i in range(l)
]

最后,由于此邻接表大概是BFS算法,因此您也可以考虑不必建立邻接表,因为在{em> 中使用{ {1}}和a当场。我想知道您是否真的通过创建邻接表来节省时间。

在您的BFS代码中,您可能会有类似的内容(其中b是“当前”节点):

i

这可以替换为:

for neighbor in al[i]:

我们还应该意识到,如果目标蹦床的步数比蹦床的数目小得多,那么就有可能在BFS搜索过程中并非所有蹦床都被访问过。在那种情况下,创建完整的邻接表将是浪费时间。