Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.

The distance between two adjacent cells is 1.

Example 1:

Input:
[[0,0,0],
[0,1,0],
[0,0,0]]

Output:
[[0,0,0],
[0,1,0],
[0,0,0]]

Example 2:

Input:
[[0,0,0],
[0,1,0],
[1,1,1]]

Output:
[[0,0,0],
[0,1,0],
[1,2,1]]

Note:

1. The number of elements of the given matrix will not exceed 10,000.
2. There are at least one 0 in the given matrix.
3. The cells are adjacent in only four directions: up, down, left and right.

## Solutions

### 1. DP

DP，设dp[i][j]为最小距离，从左上角到右下角跑一次，然后从右下角到左上角跑一次即可。

class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix: return [[]]
m, n = len(matrix), len(matrix[0])
dp = [[0x7fffffff if matrix[i][j] != 0 else 0 for j in range(n)] for i in range(m)]
for i in range(m):
for j in range(n):
self.DP(i, j, m, n, dp)
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
self.DP(i, j, m, n, dp)
return dp

def DP(self, i, j, m, n, dp):
if i > 0: dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1)
if j > 0: dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1)
if i < m - 1: dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1)
if j < n - 1: dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1)
# Runtime: 1036 ms, faster than 11.29% of Python3 online submissions for 01 Matrix.
# Memory Usage: 16.7 MB, less than 8.33% of Python3 online submissions for 01 Matrix.

### 2. DFS

class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
if not matrix:
return matrix

self.r, self.c = len(matrix), len(matrix[0])
self.directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

for i in range(self.r):
for j in range(self.c):
if matrix[i][j] == 1 and (not self.has_neighbor_zero(i, j, matrix)):
matrix[i][j] = float('inf')

for i in range(self.r):
for j in range(self.c):
if matrix[i][j] == 1:
self.dfs(matrix, i, j, -1)
return matrix

def has_neighbor_zero(self, row, col, matrix):
for dire in self.directions:
x, y = row + dire[0], col + dire[1]
if x >= 0 and x < self.r and y >= 0 and y < self.c and matrix[x][y] == 0:
return True
return False

def dfs(self, matrix, row, col, val):
if row < 0 or row >= self.r or col < 0 or col >= self.c or matrix[row][col] <= val:
return
if val > 0:
matrix[row][col] = val

for dire in self.directions:
x, y = row + dire[0], col + dire[1]
self.dfs(matrix, x, y, matrix[row][col] + 1)
# Runtime: 848 ms, faster than 37.41% of Python3 online submissions for 01 Matrix.
# Memory Usage: 16 MB, less than 25.00% of Python3 online submissions for 01 Matrix.

class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
if not matrix:
return matrix

self.r, self.c = len(matrix), len(matrix[0])
self.directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
res = [[float('inf') for _ in range(self.c)] for _ in range(self.r)]

for i in range(self.r):
for j in range(self.c):
if matrix[i][j] == 0:
self.dfs(matrix, res, i, j, 0)
return res

def dfs(self, matrix, res, row, col, dist):
if row < 0 or row >= self.r or col < 0 or col >= self.c or res[row][col] <= dist:
return

if matrix[row][col] == 0:
dist = 0

res[row][col] = dist

for dire in self.directions:
x, y = row + dire[0], col + dire[1]
self.dfs(matrix, res, x, y, dist + 1)

class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
if not matrix:
return matrix

self.r, self.c = len(matrix), len(matrix[0])
self.directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

for i in range(self.r):
for j in range(self.c):
if matrix[i][j] == 1 and not self.has_neighbor_zero(i, j, matrix):
matrix[i][j] = float('inf')

for i in range(self.r):
for j in range(self.c):
self.dfs(matrix, i, j)
return matrix

def has_neighbor_zero(self, row, col, matrix):
for dire in self.directions:
x, y = row + dire[0], col + dire[1]
if x >= 0 and x < self.r and y >= 0 and y < self.c and matrix[x][y] == 0:
return True
return False

def dfs(self, matrix, row, col):
for dire in self.directions:
x, y = row + dire[0], col + dire[1]
if x < 0 or x >= self.r or y < 0 or y >= self.c:
continue

if matrix[x][y] > matrix[row][col] + 1:
matrix[x][y] = matrix[row][col] + 1
self.dfs(matrix, x, y)
# Runtime: 892 ms, faster than 28.14% of Python3 online submissions for 01 Matrix.
# Memory Usage: 16 MB, less than 16.67% of Python3 online submissions for 01 Matrix.

### 2. BFS

class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix:
return matrix
r, c = len(matrix), len(matrix[0])
self.directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
queue = collections.deque()
for i in range(r):
for j in range(c):
if matrix[i][j] == 0:
queue.append((i, j))
else:
matrix[i][j] = float('inf')

while queue:
cur = queue.popleft()
for dire in self.directions:
x, y = cur[0] + dire[0], cur[1] + dire[1]
if x < 0 or x >= r or y < 0 or y >= c or matrix[x][y] <= matrix[cur[0]][cur[1]]:
continue
matrix[x][y] = matrix[cur[0]][cur[1]] + 1
queue.append((x, y))
return matrix
# Runtime: 972 ms, faster than 17.35% of Python3 online submissions for 01 Matrix.
# Memory Usage: 16.2 MB, less than 16.67% of Python3 online submissions for 01 Matrix.