边工作边刷题:70天一遍leetcode: day 92
Shortest Distance from All Buildings
要点:
- 这种没有weight的distance题,首先想到dfs/bfs。这题因为是最短距离,所以用bfs。注意不同于Surrounded Regions,这题不是连通渲染,而是对每个’1’值点作为起点单独的bfs,而不是并行的起始点同时进queue初始化
- 如何记录结果?bfs过程中,level是累加到某个点上的。但是并不知道是不是所有building都能到达,所以用reach来记录每个0点到达的1点(buildings)个数,最后统计的时候不考虑不能reach所有building的
- 一个强力优化:bfs同时记录某个buildings连通的其他building个数,结束时如果不为所有building数,可以直接返回-1
细节:
- bfs,visited在开始的时候allocate
- 数据结构:self.reach, self.dist, visited, count
- return True/False直接依赖一个条件的时候直接返回条件,而不要if/else检查
错误点:
- 注意bfs的起始点是每个building,统计reach和sumLen的点是经过的0,count是对连通的1。最后结果是对所有0点
- TypeError: 'int' object is not iterable: deque+pair的初始化极易错:错误:deque((x,y)),正确:deque([(x,y)])
- next从deque变成list了:最后还是用单一object计数的方法
- list comprehension中的variable不是list中local的
- d+=1的位置:每层之外,初始为0
- [[-1]]的corner case:如果bfs中初始count=0,不先set初始点的visited,这样初始点之后不能访问到,可以返回-1
from collections import deque
class Solution(object):
def shortestDistance(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
def bfs(grid, m, n, x, y, total):
visited = [[False]*n for _ in xrange(m)] # error: don't use x,y
q = deque([(x,y)]) # error 1
count=0
# visited[x][y]=True
dirs = [(1,0),(0,1),(-1,0),(0,-1)]
d = 0
while q:
# print q
ql = len(q) # error 2: use single object
d+=1
for _ in xrange(ql):
x,y = q.popleft()
for xd,yd in dirs:
x0,y0 = x+xd,y+yd
if 0<=x0<m and 0<=y0<n and not visited[x0][y0]:
visited[x0][y0]=True # error 3: dont forget
if grid[x0][y0]==0:
self.dist[x0][y0]+=d
self.reach[x0][y0]+=1
q.append((x0,y0))
if grid[x0][y0]==1:
# print x0,y0
count+=1
#print count, total
return count==total
m,n=len(grid),len(grid[0])
total = sum([val for line in grid for val in line if val==1])
self.dist = [[0 for y in xrange(n)] for x in xrange(m)]
self.reach = [[0 for y in xrange(n)] for x in xrange(m)]
for x in xrange(m):
for y in xrange(n):
if grid[x][y]==1:
if not bfs(grid, m, n, x, y, total):
return -1
shortest = sys.maxint
for x in xrange(m):
for y in xrange(n):
if self.reach[x][y]==total:
shortest = min(self.dist[x][y], shortest)
return shortest