降低python(2.7)算法的时间复杂度



我在输入中有一个列表,由三个列表组成,每个列表分别表示X、Y和Z坐标。例如:

coords = [[2, 1, 5, 2, 8, 6, 8, 6, 1, 2, 3 , 4], [1, 3, 4, 1, 2, 2, 2, 4, 2, 3, 4, 5], [2, 4, 7, 2, 1, 2, 1, 4, 5, 6, 9, 8]]

其中坐标X的列表为:X = [2, 1, 5, 2, 8, 6, 8, 6, 1, 2, 3 , 4]

一个点将形成如下:point = [2, 1, 2]。点XYZ表示立方体的顶点。(在我的程序中,我必须分析一组堆叠或并排的立方体(。

作为函数的输出,我想要一个与总点数(=其中一个坐标列表的长度(一样大的ID列表。对于不同的点,ID必须是唯一的,并且随着点列表的迭代而按顺序递增。当已经遇到一个点时(例如,当一个立方体的顶点与另一个立方体顶点重合时(,在输出列表中,该点必须具有首先遇到的相同点的ID。

示例的结果应该是outp = [1, 2, 3, 1, 5, 6, 5, 8, 9, 10, 11]

这是我写的代码,它运行得很好:

def AssignIDtoNode(coords):
outp = []
n_points = len(coords[0])
points = []
memo_set = set()
memo_lst = ["" for x in xrange(0, n_points)]
for i in range(n_points):
point = "(X = " + str(coords[0][i]) + ", Y = " + str(coords[1][i]) + ", Z = " + str(coords[2][i]) + ")"
if punto not in memo_set:
outp.append(i+1)
memo_set.add(point)
memo_lst[i] = point
else:
ind = memo_lst.index(point)
outp.append(ind+1)

return outp

当函数的输入中有一个非常大的点列表(数百万点(,并且计算时间显著增加时,就会出现问题。为了便于搜索,我将每个点转换为一个字符串,并在可能的情况下使用了一个集合来减少第一次搜索的时间。在我看来,当程序必须通过.index((函数搜索点的索引时,它会花费很长时间。

有没有办法进一步优化这个功能?

使用enumerate、zip和字典来存储索引-{(x,y,z):index,...}

def f(coords):
d = {}
outp = []
for i,punto in enumerate(zip(*coords),1):
d[punto] = d.get(punto,i)    # if it doesn't exist add it with the current index
outp.append(d[punto])

return outp

单次通过点,无类型转换,恒定时间查找。

>>> AssignIDtoNode(coords) == f(coords)
True

压缩并枚举文档


LBYL。。。

def g(coords):
outp = []
d = {}
for i,punto in enumerate(zip(*coords),1):
if punto not in d:
d[punto] = i
outp.append(d[punto])        
return outp

对于100万和300万(x,y,z(点,gf快约25%。

使用dict从点到索引的映射

def AssignIDtoNode(coords):
outp = []
n_points = len(coords[0])
points = []
memo_dict = dict()
for i in range(n_points):
point = tuple(coords[0][i],coords[1][i],coords[2][i])
if point not in memo_dict:
outp.append(i+1)
memo_dict[point] = i+1
else:
ind = memo_dict[point]
outp.append(ind+1)

return outp

您应该能够使用内部字典的列表理解在线性时间内完成这项工作:

coords = [[2, 1, 5, 2, 8, 6, 8, 6, 1, 2, 3, 4], 
[1, 3, 4, 1, 2, 2, 2, 4, 2, 3, 4, 5], 
[2, 4, 7, 2, 1, 2, 1, 4, 5, 6, 9, 8]]
IDs = [d[c] for d in [dict()] for c in zip(*coords) if d.setdefault(c,len(d)+1)]
print(IDs)
# [1, 2, 3, 1, 4, 5, 4, 6, 7, 8, 9, 10]

最新更新