题目描述:
给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。两个相邻元素间的距离为 1 。
示例 1:
输入:
0 0 0
0 1 0
0 0 0
输出:
0 0 0
0 1 0
0 0 0
示例 2:
输入:
0 0 0
0 1 0
1 1 1
输出:
0 0 0
0 1 0
1 2 1
解题思路:
对于矩阵中的任意一个 1 以及一个 0,我们如何从这个 1 到达 0 并且距离最短呢?根据上面的做法,我们可以从 1 开始,先在水平方向移动,直到与 0 在同一列。随后再在竖直方向上移动,直到到达 0 的位置。这样以来,从一个固定的 1 走到任意一个 0,在距离最短的前提下可能有四种方法:
- 只有 水平向左移动 和 竖直向上移动;
- 只有 水平向左移动 和 竖直向下移动;
- 只有 水平向右移动 和 竖直向上移动;
- 只有 水平向右移动 和 竖直向下移动。
这样以来,我们就可以使用动态规划解决这个问题了。我们用
f
(
i
,
j
)
f(i,j)
f(i,j) 表示位置
(
i
,
j
)
(i, j)
(i,j) 到最近的
0
0
0 的距离。如果我们只能「水平向左移动」和「竖直向上移动」,那么我们可以向上移动一步,再移动
f
(
i
−
1
,
j
)
f(i - 1, j)
f(i−1,j) 步到达某一个
0
0
0,也可以向左移动一步,再移动
f
(
i
,
j
−
1
)
f(i, j - 1)
f(i,j−1) 步到达某一个
0
0
0。因此我们可以写出如下的状态转移方程:
对于另外三种移动方法,我们也可以写出类似的状态转移方程,得到四个
f
(
i
,
j
)
f(i, j)
f(i,j)的值,那么其中最小的值就表示位置
(
i
,
j
)
(i, j)
(i,j)到最近的0的距离。
实际上,只需要以下两种情况:
- 只有 水平向左移动 和 竖直向上移动;
- 只有 水平向右移动 和 竖直向下移动。
代码:
class Solution:
def updateMatrix(self, matrix):
m, n = len(matrix), len(matrix[0])
# 初始化动态规划的数组,所有的距离值都设置为一个很大的数
dist = [[10**9] * n for _ in range(m)]
# 如果 (i, j) 的元素为 0,那么距离为 0
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
dist[i][j] = 0
# 只有 水平向左移动 和 竖直向上移动,注意动态规划的计算顺序
for i in range(m):
for j in range(n):
if i - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1)
if j - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1)
# 只有 水平向右移动 和 竖直向下移动,注意动态规划的计算顺序
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
if i + 1 < m:
dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1)
if j + 1 < n:
dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1)
return dist
s = Solution()
matrix = [[0,0,0],[0,1,0],[1,1,1]]
print(s.updateMatrix(matrix))
参考链接:
https://leetcode-cn.com/problems/01-matrix/solution/01ju-zhen-by-leetcode-solution/
题目来源: