1.题目
2.题目意思
矩阵由01组成,找出矩阵每个元素到最近的0的距离。显然,0到0的距离就是0.
3.代码
解法一:
class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
m, n = len(matrix), len(matrix[0])
Q = collections.deque([])
visited = set()
# 初始化队列,将所有起始点加入
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
Q.append((i, j))
visited.add((i, j))
# 将所有相邻节点加入队列
while Q:
i, j = Q.popleft()
for x, y in [(i+1, j), (i-1, j), (i, j+1), (i, j-1)]:
if 0 <= x < m and 0 <= y < n and (x, y) not in visited:
matrix[x][y] = matrix[i][j] + 1
visited.add((x, y))
Q.append((x, y))
return matrix
思路:队列+bfs~
用bfs就得用到队列~就像用dfs就得用到递归。所以,Q = collections.deque([])
构建了一个双端队列,可从队列左右增加,删减数值。同时构建一个集合visited
来记录哪些元素访问过。
接下来进行初始化,如果矩阵值等于0,加入队列Q,并加入visited
。加入visited
是因为等于0最近的就是0,就不用再重复计算了。加入队列是因为,从0开始计算周边非0单位的距离。另外,其实visited
不用集合,用列表也行,因为只会进去一次,但是居然超出时间限制了。。。查了一下,set
的搜索速度快的一批,相当的快,在数据量较大的情况下,能比list快5500倍,而且数据量越大,越快。另外,用个set进行维护实际上就是空间换时间~
接下里就是访问双端队列的每一个元素,每次从队列左边弹出,访问上下左右四个元素。如果该元素没访问过(即not in visited
),则该元素距离+1,加入队列。因为他旁边是0嘛。然后这个元素出列的时候,他旁边没访问过的元素就是再+1,就变成2了,这也是实现的关键所在。你品,你细品~
解法二:
class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
m, n = len(matrix), len(matrix[0])
for i in range(m):
for j in range(n):
if matrix[i][j] == 1:
matrix[i][j] = m*n
if i>0:
matrix[i][j] = min(matrix[i][j], matrix[i-1][j]+1)
if j>0:
matrix[i][j] = min(matrix[i][j], matrix[i][j-1]+1)
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
if i < m-1:
matrix[i][j] = min(matrix[i][j], matrix[i+1][j]+1)
if j < n-1:
matrix[i][j] = min(matrix[i][j], matrix[i][j+1]+1)
return matrix
思路:dp
这个dp很简单,初始化时,0就是0,非0给他换成一个很大的数。原因后面说。
然后正向dp,比较右边和下面的元素(如果存在的话),如果自己小就取自己(比如自己是0),如果别的小,就取别人+1。这就是为啥一开始初始化要换掉的原因。因为我们是原地操作,所以原矩阵的1代表次数是1,新矩阵的1代表的是距离为1,此1非彼1,初始化换大一点实际上就是把距离初始为无穷大。
然后再反向dp,比较左边和上边的元素,就完了。
因为是原地操作,所以内存占用很小,轻易超过100%。
解法三:
思路:dfs
我放弃dfs了,搞半天没搞明白,画图思考发现bfs真好啊,我真是醉了,有机会再来搞把,晕了
总的来说,都还行,冲冲冲~