# 第71期-基础算法:动态规划 01矩阵

Python是一门需要不断实践练习的编程语言,本文档将AI大学堂学员交流群的Python每周练习进行汇总,希望各位小伙伴能够多进行实践练习,逐渐爱上这门神奇的编程语言,掌握它并在生活中能够使用它。

# 1 问题描述

给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。两个相邻元素间的距离为 1 。

示例 1:

image.jpg
输入: mat = [[0,0,0],[0,1,0],[0,0,0]]
输出: [[0,0,0],[0,1,0],[0,0,0]]

示例 2:

image.jpg
输入: mat = [[0,0,0],[0,1,0],[1,1,1]]
输出: [[0,0,0],[0,1,0],[1,2,1]]

初始代码

from typing import List
class Solution:
    def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
        #在此之间填写代码

print(Solution().updateMatrix([[0,0,0],[0,1,0],[0,0,0]]))
print(Solution().updateMatrix([[0,0,0],[0,1,0],[1,1,1]]))
1
2
3
4
5
6
7

# 2 解题思路

  • 标签:动态规划
  • 首先把每个源点 0 入队,然后从各个 0 同时开始一圈一圈的向 1 扩散
  • 扩散过程中可以把所有的1变成-1,这样不会担心距离一与原本的一弄混

# 3 解题方法

from typing import List
class Solution:
    def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
        queue=[]
        a,b=len(mat),len(mat[0])
        for i in range(a):
            for j in range(b):
                if mat[i][j]==1:mat[i][j]=-1
                if mat[i][j]==0:queue.append((i,j))
        x=0
        while x<len(queue):
            cur = queue[x]
            for i,j in [(1,0),(-1,0),(0,1),(0,-1)]:
                if 0<=cur[0]+i<a and 0<=cur[1]+j<b and mat[cur[0]+i][cur[1]+j]==-1:
                    mat[cur[0]+i][cur[1]+j]=mat[cur[0]][cur[1]]+1
                    queue.append((cur[0]+i,cur[1]+j))
            x+=1
        return mat

print(Solution().updateMatrix([[0,0,0],[0,1,0],[0,0,0]]))
print(Solution().updateMatrix([[0,0,0],[0,1,0],[1,1,1]]))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

第1-3,21-22行: 题目中已经给出的信息,运行代码时要根据这些代码进行编辑
第4行: 定义列表queue用于存放需要遍历的节点
第5行: 定义变量a、b分别用于存放矩阵的长和宽
第6-7行: 使用for循环遍历矩阵中的每一个值
第8行: 将矩阵中的1全部标记为-1
第9行: 将举证中的0行列索引全部加到列表queue中
第10行: 定义变量x=0用于矩阵索引
第11行: 当未遍历完矩阵中的所有元素时,继续循环
第12行: 定义变量cur用于存放第一个需要扩散变量的位置
第13行: for循环用于遍历该点的四个扩散方向
第14行: 判断扩散方向的点是否在矩阵内部且数值为-1时(也就是还未扩散)
第15行: 改变该点的数值为扩散源头的数值加一,表示距离加一
第16行: 在queue列表中加入该点,用于以后该点扩散
第17行: 索引值加一,进行下一个点的扩散
第18行: 当全部遍历完成之后,返回遍历之后的列表

代码运行结果为:
image.jpg

# 算法讲解

这里用到了基础算法:动态规划,简单讲解下这个算法:
动态规划
动态规划(Dynamic programming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。 动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。


性质


1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。


2. 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。


3. 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。


性质


1. 划分:按照问题的特征,把问题分为若干阶段。注意:划分后的阶段一定是有序的或者可排序的


2. 确定状态和状态变量:将问题发展到各个阶段时所处的各种不同的客观情况表现出来。状态的选择要满足无后续性


3. 确定决策并写出状态转移方程:状态转移就是根据上一阶段的决策和状态来导出本阶段的状态。根据相邻两个阶段状态之间的联系来确定决策方法和状态转移方程


4. 边界条件:状态转移方程是一个递推式,因此需要找到递推终止的条件

# 4 视频解析

高清视频讲解,请查看AI大学堂Python基础实战100例 (opens new window)
关注『讯飞AI大学堂』公众号,发送 python100 即可领取Python基础实战100例源代码
AI大学堂公众号.png

更新于: 12/28/2021, 7:43:14 AM