检查一个值为 1 的单元格是否存在路径到达矩阵的右下角,且在任何值为 2 的单元格到达之前。
涉及网格和矩阵的问题大多使用 BFS 或 DFS 遍历算法解决。先来看一下第一个算法:
广度优先遍历 - BFS 或广度优先遍历是一种用于搜索树或图数据结构的算法。它从根节点开始,在移动到下一层之前探索当前层的所有节点。
算法
procedure BFS(G, root) is
let Q be a queue
label root as explored
Q.enqueue(root)
while Q is not empty do
v := Q.dequeue()
if v is the goal then
return v
for all edges from v to w in G.adjacentEdges(v) do
if w is not labelled as explored then
label w as explored
w.parent := v
Q.enqueue(w)
问题陈述
给定一个矩阵 arr[][],其中只有 0、1 和 2。任务是找出 1 是否可以在 2 之前到达矩阵的右下角。
约束条件
矩阵中可以存在多个 2,但只能存在一个 1。
1 和 2 都可以向四个方向移动,即上、下、左和右,但只能移动到值为 0 的单元格。
示例 1
输入
arr[][] =
{{0, 2, 0},
{0, 2, 0},
{0, 1, 0}}
输出
True
解释
1 可以用 1 步 (R) 到达右下角,而 2 需要 2 步 (RD)。因此,1 在 2 之前到达右下角。
示例 2
输入
arr[][] =
{{0, 2, 0},
{0, 1, 0},
{0, 2, 0}}
输出
False
解释
2 可以用 1 步 (R) 到达右下角,而 1 需要 2 步 (RD)。因此,2 在 1 之前到达右下角。
解决方案方法:广度优先搜索遍历
使用双端队列数据结构,我们对矩阵应用 BFS 以查找 1 是否在 2 之前到达右下角。在双端队列中,将 1 推入前端,将 2 推入后端,以便如果 1 和 2 同时到达,则优先考虑 1。然后从双端队列中弹出元素,并查看是否可以到达右下角。
伪代码
function oneTwo(arr: 2D array of integers):
n := number of rows of arr
m := number of columns of arr
q := empty deque of vectors of integers
for i from 0 to n-1:
for j from 0 to m-1:
if arr[i][j] is 1:
push {i, j, 1} to front of q
else if arr[i][j] is 2:
push {i, j, 2} to back of q
set arr[i][j] to 0
del_x := [0, 1, 0, -1]
del_y := [-1, 0, 1, 0]
while q is not empty:
front := q.front()
pop front element from q
i := front[0]
j := front[1]
num := front[2]
if arr[i][j] is not 0:
continue
set arr[i][j] to 1
if num is 1 and (i is n-1 and j is m-1):
return True
for d from 0 to 3:
neighbour_i := i + del_x[d]
neighbour_j := j + del_y[d]
if neighbour_i is between 0 and n-1 and neighbour_j is between 0 and m-1:
push {neighbour_i, neighbour_j, num} to back of q
return False
示例:C++ 实现
以下程序使用 BFS 遍历算法。
#include <bits/stdc++.h>
using namespace std;
// Function to find if 1 reaches bottom right corner before 2
bool oneTwo(vector<vector<int>> &arr){
int n = arr.size();
int m = arr[0].size();
deque<vector<int>> q;
// Adding 1 to front of queue and 2 to back of queue
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (arr[i][j] == 1) {
q.push_front({i, j, 1});
} else if (arr[i][j] == 2) {
q.push_back({i, j, 2});
}
arr[i][j] = 0;
}
}
int del_x[] = {0, 1, 0, -1};
int del_y[] = {-1, 0, 1, 0};
while (!q.empty()) {
auto front = q.front();
q.pop_front();
int i = front[0], j = front[1], num = front[2];
if (arr[i][j]) {
continue;
}
arr[i][j] = 1;
// Checking if 1 reached the bottom right corner first
if (num == 1 and (i == n - 1 && j == m - 1)) {
return true;
}
for (int d = 0; d < 4; d++) {
int neighbour_i = i + del_x[d];
int neighbour_j = j + del_y[d];
if (neighbour_i >= 0 and neighbour_i < n and neighbour_j >= 0 and neighbour_j < m) {
q.push_back({neighbour_i, neighbour_j, num});
}
}
}
return false;
}
int main(){
vector<vector<int>> arr{{0, 2, 0},
{0, 2, 0},
{0, 1, 0}};
if (oneTwo(arr)){
cout << "True";
} else {
cout << "False";
}
return 0;
}
输出
True
时间复杂度 - O(N*M),其中 N*M 是矩阵的维度。这是因为我们遍历了矩阵中的所有元素。
空间复杂度 - O(N*M),其中 N*M 是矩阵的维度。这是因为双端队列存储了矩阵的所有可能方向。
结论
总之,提供的解决方案使用了多源 BFS 并使用了双端队列数据结构来优先考虑 1 而不是 2。解决方案的时间和空间复杂度为 O(N*M),其中 N*M 是矩阵的维度。
广告
数据结构
网络
关系型数据库管理系统
操作系统
Java
iOS
HTML
CSS
Android
Python
C 编程
C++
C#
MongoDB
MySQL
Javascript
PHP