通过动态规划,从四个方向进行状态转移。

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        dp=[[10000 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):  
                if matrix[i][j]==0:
                    dp[i][j]=0    

        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                if i-1>=0:
                    dp[i][j]=min(dp[i-1][j]+1,dp[i][j])
                if j-1>=0:
                    dp[i][j]=min(dp[i][j-1]+1,dp[i][j])

        for i in range(len(matrix)-1,-1,-1):
            for j in range(len(matrix[0])-1,-1,-1):
                if i+1<len(matrix):
                   dp[i][j]=min(dp[i+1][j]+1,dp[i][j])
                if j+1<len(matrix[0]):
                    dp[i][j]=min(dp[i][j],dp[i][j+1]+1)

        for i in range(len(matrix)):
            for j in range(len(matrix[0])-1,-1,-1):
                if i-1>=0:
                   dp[i][j]=min(dp[i-1][j]+1,dp[i][j])
                if j+1<len(matrix[0]):
                    dp[i][j]=min(dp[i][j],dp[i][j+1]+1)

        for i in range(len(matrix)-1,-1,-1):
            for j in range(len(matrix[0])):
                if i+1<len(matrix):
                   dp[i][j]=min(dp[i+1][j]+1,dp[i][j])
                if j-1>=0:
                    dp[i][j]=min(dp[i][j],dp[i][j-1]+1)

        return dp

然后发现从两个方向遍历就可以,左下和右上,向右向下的移动,和向左向上的移动。

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        dp=[[10000 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):  
                if matrix[i][j]==0:
                    dp[i][j]=0    


        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                if i-1>=0:
                    dp[i][j]=min(dp[i-1][j]+1,dp[i][j])
                if j-1>=0:
                    dp[i][j]=min(dp[i][j-1]+1,dp[i][j])

        for i in range(len(matrix)-1,-1,-1):
            for j in range(len(matrix[0])-1,-1,-1):
                if i+1<len(matrix):
                   dp[i][j]=min(dp[i+1][j]+1,dp[i][j])
                if j+1<len(matrix[0]):
                    dp[i][j]=min(dp[i][j],dp[i][j+1]+1)


        return dp

在一个图中,能从一个点出发求这种最短距离的方法很容易想到就是 BFS,BFS 的名称是广度优先遍历,即把周围这一圈搜索完成之后,再搜索下一圈,是慢慢扩大搜索范围的。

作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/01-matrix/solution/tao-lu-da-jie-mi-gao-dong-ti-mu-kao-cha-shi-yao-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

注意:
求图中的最短路径选择BFS算法
是一圈一圈的搜索,当满足条件了就把距离输出。
每次步数加1是在每一圈结束,每一圈整体会加一步
使用visit数组记录,不要用(x,y)in visit判断这样会浪费很多时间
求1到0的距离时,这种多源的题要反过来,求0到1的最短,入队0元素,求到1的最短距离。
如果将1入队,求得是与1最近的0,这里的问题也是超级源点的问题,如果矩阵中只有一个0,那么1到0的距离就要从0开始进行计算,但是现在的问题是有多个0,那么就是把多个0看作有一个超级源点链接。
图片说明
见题解 https://leetcode-cn.com/problems/01-matrix/solution/01ju-zhen-by-leetcode-solution/

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        queue=collections.deque()
        directions=[(0,1),(1,0),(-1,0),(0,-1)]
        result=[[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
        visit=[[0]*len(matrix[0]) for _ in range(len(matrix))]
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                if matrix[i][j]==0:
                    queue.append((i,j))
                    visit[i][j]=1
        step=0

        while queue:
            size=len(queue)
            for i in range(size):
                x,y=queue.popleft()

                if matrix[x][y]==1:
                    result[x][y]=step

                for item in directions:
                    if x+item[0]<len(matrix) and x+item[0]>=0 and y+item[1]<len(matrix[0]) and y+item[1]>=0 and  visit[x+item[0]][y+item[1]]!=1 :

                        queue.append((x+item[0],y+item[1]))
                        visit[x+item[0]][y+item[1]]=1
                    else:
                        continue

            step+=1
        return result

同样可以通过matrix数组本身得到结果,这样需要matrix中的1的位置替换成-1 来标识未访问节点。
也可以通过result数组result[x][y]+=1得到结果,这样的话就不用每次for循环遍历队列当前长度,来控制这次的遍历整体移动一步了。

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        queue=collections.deque()

        directions=[(0,1),(1,0),(-1,0),(0,-1)]

        result=[[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]


        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                if matrix[i][j]==0:
                    queue.append((i,j))
                else:
                    matrix[i][j]=-1


        while queue:

                x,y=queue.popleft()

                # if matrix[x][y]==1:
                #     result[x][y]=step

                for item in directions:
                    if x+item[0]<len(matrix) and x+item[0]>=0 and y+item[1]<len(matrix[0]) and y+item[1]>=0 and  matrix[x+item[0]][y+item[1]]==-1 :

                        matrix[x+item[0]][y+item[1]]=matrix[x][y]+1
                        queue.append((x+item[0],y+item[1]))


        return matrix