542. 01 矩阵
给定一个由 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
注意:
- 给定矩阵的元素个数不超过 10000。
- 给定矩阵中至少有一个元素是 0。
- 矩阵中的元素只在四个方向上相邻: 上、下、左、右。
这道题应用的是广度优先搜索(BFS算法),是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。
BFS算法,一般是用队列实现,先进先出。其主要原理是,使用队列保存未被查询过的结点。
最简单的例子就是:我们丢了东西,首先会在自己的周围找,如果周围没找到,那么就会想远一点的地方,然后去找。
下面是BFS算法的常用模块:
BFS: #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=100; bool vst[maxn][maxn]; // 访问标记 int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量 struct State // BFS 队列中的状态数据结构 { int x,y; // 坐标位置 int Step_Counter; // 搜索步数统计器 }; State a[maxn]; bool CheckState(State s) // 约束条件检验 { if(!vst[s.x][s.y] && ...) // 满足条件 return 1; else // 约束条件冲突 return 0; } void bfs(State st) { queue <State> q; // BFS 队列 State now,next; // 定义2 个状态,当前和下一个 st.Step_Counter=0; // 计数器清零 q.push(st); // 入队 vst[st.x][st.y]=1; // 访问标记 while(!q.empty()) { now=q.front(); // 取队首元素进行扩展 if(now==G) // 出现目标态,此时为Step_Counter 的最小值,可以退出即可 { ...... // 做相关处理 return; } for(int i=0;i<4;i++) { next.x=now.x+dir[i][0]; // 按照规则生成下一个状态 next.y=now.y+dir[i][1]; next.Step_Counter=now.Step_Counter+1; // 计数器加1 if(CheckState(next)) // 如果状态满足约束条件则入队 { q.push(next); vst[next.x][next.y]=1; //访问标记 } } q.pop(); // 队首元素出队 } return; } int main() { ...... return 0; }
对于此题,我们用java来写。我们分析道,题目要求必须含有零,那么我们可以把所有0入队,把1置为MAX_VALUE,然后把最靠近0的1的距离算出来,然后将他们入队,再算距离最靠近0的1的1的距离算出来,依次处理
class Solution { public List<List<Integer>> updateMatrix(List<List<Integer>> matrix) { if (matrix == null || matrix.size() == 0) return matrix; int m = matrix.size(); int n = matrix.get(0).size(); Queue<int[]> q = new LinkedList<>(); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { // 把0元素加入队列中,以备波及影响周围元素 if (matrix.get(i).get(j) == 0) q.offer(new int[] { i, j }); else // 设为最大值,方便求0元素影响值 matrix.get(i).set(j, Integer.MAX_VALUE); } // 上下左右 int[][] dirs = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; while (!q.isEmpty()) { int cell[] = q.poll(); for (int[] d : dirs) { int row = cell[0] + d[0]; int col = cell[1] + d[1]; if (row < 0 || row >= m || col < 0 || col >= n) continue; // 上下左右取到的值 int value = matrix.get(row).get(col); int tmp = matrix.get(cell[0]).get(cell[1]) + 1; // 如果value小,那说明之前已经更新过,不是max if (value <= tmp) continue; q.offer(new int[] { row, col }); matrix.get(row).set(col, tmp); } } return matrix; } }
def updateMatrix(self, matrix): if not matrix or not matrix[0]: return matrix M, N = len(matrix), len(matrix[0]) cur = set() for i in range(M): for j in range(N): if matrix[i][j] == 1: for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if -1 < ni < M and -1 < nj < N and matrix[ni][nj] == 0: cur.add((i, j)) matrix[i][j] = -1 break distance = 1 while cur: nxt = set() distance += 1 for i, j in cur: for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if -1 < ni < M and -1 < nj < N and matrix[ni][nj] == 1: matrix[ni][nj] = distance nxt.add((ni, nj)) cur = nxt for i in range(M): for j in range(N): if matrix[i][j] == -1: matrix[i][j] = 1 return matrix