我目前正在做一个项目,我必须多次检查给定的2D点是否合法",即它是否在网格边界内并且如果之前没有访问过。网格有一个固定的H x W
大小,所以我想我可以将它们存储在一个集合中,而不是一个2D查找表。令我惊讶的是,它比检查它是否出现在一个集合中要慢得多,即使它(理论上)是一个O(logn)
操作,而不是O(1)
一个简单的操作数组查找。
首先尝试:
class PointSet:
def __init__(self, h, w):
if h <= 0 or w <= 0:
raise ValueError("Invalid size")
self.h = h
self.w = w
self.lookup = [[False for _ in range(w)] for _ in range(h)]
self.size = 0
def add(self, point):
r, c = point
self.lookup[r][c] = True
self.size += 1
def remove(self, point):
r, c = point
self.lookup[r][c] = False
self.size -= 1
def __contains__(self, point):
r, c = point
return 0 <= r < self.h and 0 <= c < self.w and self.lookup[r][c]
def __bool__(self):
return self.size != 0
def __len__(self):
return self.size
# H, W = ...
# pointset = PointSet(H, W)
# if (3, 5) in pointset:
# ...
第二次尝试:
# pointset = set()
# if (3, 5) in pointset:
# ...
第二代码执行得更快。为什么会这样?
答案 0 :(得分:1)
首先,您必须考虑__contains__
方法的实现调用__getitem__
两次(因为您有一个列表列表),每个方法都有0(1)个复杂度,并将评估两个链式比较(0 <= r < self.h
和0 <= c < self.w
);在最坏的情况下,评估所有表达式,因为and
只会在第一个False
上短路。前一行中的可迭代解包会产生额外的开销。属性查找还有一些小的补充。
集合的成员资格查找只是简单的0(1),所以我看不到你的代码可能会如何击败它。