1 介绍
本博客用来记录灵神力扣题单之网格图。
2 训练
2.1 例题
解题思路:bfs。模拟。状态表示为(x,y,s)
表示蛇尾在(x,y)
位置处,s=0
表示水平方向,s=1
表示竖直方向。无论水平方向还是竖直方向,
(1)向下移动:x
增加1,y和s不变。用三元组(1,0,0)
表示。前两个元素是加,后一个元素是异或。
(2)向右移动:y
增加1,x
和s
不变。用三元组(0,1,0)
表示。
(3)旋转:s
切换,即0
变为1
,1
变为0
。x
和y
不变。用三元组(0,0,1)
表示。此操作需要保证(x+1,y+1)
处没有障碍物。
蛇尾在(x,y)
处,则蛇头在(x+s,y+1-s)
处。
C++代码如下,
class Solution {
public:
int minimumMoves(vector<vector<int>>& grid) {
int n = grid.size();
bool st[100][100][2];
memset(st, 0, sizeof st);
int dist[100][100][2];
memset(dist, 0, sizeof dist);
if (grid[0][0] == 1 || grid[0][1] == 1 || grid[n-1][n-2] == 1 || grid[n-1][n-1] == 1) { //特判
return -1;
}
tuple<int,int,int> snode(0,0,0);
tuple<int,int,int> enode(n-1,n-2,0);
queue<tuple<int,int,int>> q;
q.push(snode);
st[0][0][0] = true;
dist[0][0][0] = 0;
int dirs[3][3] = {{1,0,0}, {0,1,0}, {0,0,1}}; //{dx,dy,ds}前2个元素是加,后一个元素是异或
while (!q.empty()) {
auto [x, y, s] = q.front();
if (x == n-1 && y == n-2 && s == 0) { //提前退出
return dist[x][y][s];
}
q.pop();
for (int k = 0; k < 3; ++k) {
int nx = x + dirs[k][0];
int ny = y + dirs[k][1];
int ns = s ^ dirs[k][2];
//蛇尾(nx,ny),蛇头(nx+ns,ny+1-ns)
if (nx+ns >= n || ny+1-ns >= n) {
continue; //蛇头超过范围,则跳过
}
if (grid[nx][ny] == 1 || grid[nx+ns][ny+1-ns] == 1) {
continue; //蛇身有障碍物,则跳过
}
if (st[nx][ny][ns]) {
continue; //访问过了,则跳过
}
if (k == 2 && grid[x+1][y+1] == 1) {
continue; //执行翻转操作时,有障碍物,则跳过
}
tuple<int,int,int> node(nx,ny,ns);
q.push(node);
st[nx][ny][ns] = true;
dist[nx][ny][ns] = dist[x][y][s] + 1;
}
}
return -1;
}
};
//超出时间限制,应当是map的插入耗时
class Node {
public:
int a = 0;
int b = 0;
int c = 0;
int d = 0;
Node(int a1, int b1, int c1, int d1) : a(a1), b(b1), c(c1), d(d1) {}
bool is_equal(const Node& t) const {
return a == t.a && b == t.b && c == t.c && d == t.d;
}
bool operator<(const Node& t) const { //作为map的键,需要重载<
vector<int> vec1 = {a,b,c,d};
vector<int> vec2 = {t.a, t.b, t.c, t.d};
return vec1 < vec2;
}
};
class Solution {
public:
int minimumMoves(vector<vector<int>>& grid) {
int n = grid.size();
Node snode(0,0,0,1);
Node enode(n-1,n-2,n-1,n-1);
if (grid[0][0] == 1 || grid[0][1] == 1 || grid[n-1][n-2] == 1 || grid[n-1][n-1] == 1) {
return -1; //特判
}
queue<Node> q;
q.push(snode);
map<Node, int> dist;
map<Node, bool> st;
dist[snode] = 0;
st[snode] = true;
while (!q.empty()) {
auto curr = q.front();
q.pop();
if (curr.is_equal(enode)) { //提前退出
return dist[enode];
}
int a = curr.a;
int b = curr.b;
int c = curr.c;
int d = curr.d;
//cout << "a = " << a << ", b = " << b << ", c = " << c << ", d = " << d << endl;
if (a == c) { //当前状态是水平方向
//case1: (a,b,c,d) => (a,b+1,c,d+1)
Node t(a,b+1,c,d+1);
//cout << "here a = " << t.a << ", b = " << t.b << ", c = " << t.c << ", d = " << t.d << endl;
//cout << "here, st[t] = " << st[t] << endl;
if (d+1 < n && !st[t] && grid[c][d+1] == 0) {
q.push(t);
dist[t] = dist[curr] + 1;
st[t] = true;
}
//case2: (a,b,c,d) => (a+1,b,c+1,d)
t = Node(a+1,b,c+1,d);
if (a+1 < n && !st[t] && grid[a+1][b] == 0 && grid[c+1][d] == 0) {
q.push(t);
dist[t] = dist[curr] + 1;
st[t] = true;
}
//case3: (a,b,c,d) => (a,b,c+1,d-1)
t = Node(a,b,c+1,d-1);
if (c+1 < n && !st[t] && grid[c+1][d-1] == 0 && grid[c+1][d] == 0) {
q.push(t);
dist[t] = dist[curr] + 1;
st[t] = true;
}
} else if (b == d) {//当前状态是竖直方向
//case1: (a,b,c,d) => (a+1,b,c+1,d)
Node t(a+1,b,c+1,d);
if (c+1 < n && !st[t] && grid[c+1][d] == 0) {
q.push(t);
st[t] = true;
dist[t] = dist[curr] + 1;
}
//case2: (a,b,c,d) => (a,b+1,c,d+1)
t = Node(a,b+1,c,d+1);
if (b+1 < n && !st[t] && grid[a][b+1] == 0 && grid[c][d+1] == 0) {
q.push(t);
st[t] = true;
dist[t] = dist[curr] + 1;
}
//case3: (a,b,c,d) => (a,b,c-1,d+1)
t = Node(a,b,c-1,d+1);
if (d+1 < n && !st[t] && grid[c-1][d+1] == 0 && grid[c][d+1] == 0) {
q.push(t);
st[t] = true;
dist[t] = dist[curr] + 1;
}
}
}
return -1;
}
};
python3代码如下,
class Solution:
def minimumMoves(self, grid: List[List[int]]) -> int:
n = len(grid)
st = [[[False] * 2 for _ in range(n)] for _ in range(n)]
dist = [[[0] * 2 for _ in range(n)] for _ in range(n)]
q = collections.deque([])
snode = [0,0,0]
enode = [n-1,n-2,0]
if grid[0][0] == 1 or grid[0][1] == 1 or grid[n-1][n-2] == 1 or grid[n-1][n-1] == 1: #特判
return -1
q.append(snode)
st[0][0][0] = True
dist[0][0][0] = 0
dirs = [[1,0,0],[0,1,0],[0,0,1]]
while len(q) > 0:
x,y,s = q.popleft()
if x == n-1 and y == n-2 and s == 0: #提前判断
return dist[x][y][s]
for k in range(3):
nx = x + dirs[k][0]
ny = y + dirs[k][1]
ns = s ^ dirs[k][2]
#蛇尾在(nx,ny),那么蛇头在(nx+ns,ny+1-ns)
if nx+ns >= n or ny+1-ns >= n: #超出范围,则跳过
continue
if grid[nx][ny] == 1 or grid[nx+ns][ny+1-ns] == 1:
continue #有障碍物,则跳过
if st[nx][ny][ns]:
continue #访问过了,则跳过
if k == 2 and grid[x+1][y+1] == 1:
continue #如果是翻转操作,则需要额外判断
st[nx][ny][ns] = True
dist[nx][ny][ns] = dist[x][y][s] + 1
q.append([nx,ny,ns])
return -1
class Solution:
def minimumMoves(self, grid: List[List[int]]) -> int:
n = len(grid)
q = collections.deque([])
if grid[0][0] == 1 or grid[0][1] == 1 or grid[n-1][n-2] == 1 or grid[n-1][n-1] == 1:
return -1 #特判不能抵达
snode = (0,0,0,1)
enode = (n-1,n-2,n-1,n-1)
st = collections.defaultdict(bool)
dist = collections.defaultdict(int)
q.append(snode)
dist[snode] = 0
while len(q) > 0:
a,b,c,d = q.popleft()
if enode == (a,b,c,d): #提前判断
return dist[enode]
if a == c: #当前状态是水平方向
#case1: a,b,c,d => a,b+1,c,d+1
t = (a,b+1,c,d+1)
if d+1 < n and not st[t] and grid[c][d+1] == 0:
q.append(t)
dist[t] = dist[(a,b,c,d)] + 1
st[t] = True
#case2: a,b,c,d => a+1,b,c+1,d
t = (a+1,b,c+1,d)
if a+1 < n and not st[t] and grid[a+1][b] == 0 and grid[c+1][d] == 0:
q.append(t)
dist[t] = dist[(a,b,c,d)] + 1
st[t] = True
#case3: a,b,c,d => a,b,c+1,d-1
t = (a,b,c+1,d-1)
if c+1 < n and not st[t] and grid[c+1][d-1] == 0 and grid[c+1][d] == 0:
q.append(t)
dist[t] = dist[(a,b,c,d)] + 1
st[t] = True
elif b == d: #当前状态是竖直方向
#case1: a,b,c,d => a+1,b,c+1,d
t = (a+1,b,c+1,d)
if c+1 < n and not st[t] and grid[c+1][d] == 0:
q.append(t)
dist[t] = dist[(a,b,c,d)] + 1
st[t] = True
#case2: a,b,c,d => a,b+1,c,d+1
t = (a,b+1,c,d+1)
if b+1 < n and not st[t] and grid[a][b+1] == 0 and grid[c][d+1] == 0:
q.append(t)
dist[t] = dist[(a,b,c,d)] + 1
st[t] = True
#case3: a,b,c,d => a,b,c-1,d+1
t = (a,b,c-1,d+1)
if d+1 < n and not st[t] and grid[c-1][d+1] == 0 and grid[c][d+1] == 0:
q.append(t)
dist[t] = dist[(a,b,c,d)] + 1
st[t] = True
return -1
2.2 DFS
题目2:200. 岛屿数量
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int res = 0;
vector<vector<bool>> st(n, vector<bool>(m, false));
function<void(int,int)> dfs =[&] (int i, int j) -> void {
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
continue; //超出了范围,则跳过
}
if (grid[ni][nj] == '0') {
continue; //不是陆地,则跳过
}
if (st[ni][nj]) {
continue; //访问过了,则跳过
}
dfs(ni,nj);
}
return;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j] && grid[i][j] == '1') {
dfs(i,j);
res += 1;
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
n, m = len(grid), len(grid[0])
res = 0
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
def dfs(i: int, j: int) -> None:
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue #超出范围,则跳过
if grid[ni][nj] == '0':
continue #不是陆地,则跳过
if st[ni][nj]:
continue #访问过了,则跳过
dfs(ni,nj)
return
for i in range(n):
for j in range(m):
if not st[i][j] and grid[i][j] == '1':
dfs(i,j)
res += 1
return res
题目3:695. 岛屿的最大面积
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int res = 0;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
function<int(int,int)> dfs =[&] (int i, int j) -> int {
int res = 1;
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] == 0) continue;
if (st[ni][nj]) continue;
res += dfs(ni,nj);
}
return res;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j] && grid[i][j] == 1) {
int ans = dfs(i,j);
res = max(res, ans);
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
res = 0
st = [[False] * m for _ in range(n)]
dirs = [[-1,0], [1,0], [0,-1], [0,1]]
def dfs(i: int, j: int) -> int:
res = 1
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == 0:
continue
if st[ni][nj]:
continue
res += dfs(ni, nj)
return res
for i in range(n):
for j in range(m):
if grid[i][j] == 1 and not st[i][j]:
ans = dfs(i,j)
res = max(res, ans)
return res
题目4:面试题 16.19. 水域大小
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
vector<int> pondSizes(vector<vector<int>>& land) {
int n = land.size();
int m = land[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
vector<int> res;
function<int(int,int)> dfs =[&] (int i, int j) -> int {
int res = 1;
st[i][j] = true;
for (int di = -1; di < 2; di++) {
for (int dj = -1; dj < 2; dj++) {
if (di == 0 && dj == 0) continue;
int ni = i + di;
int nj = j + dj;
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (land[ni][nj] != 0) continue;
if (st[ni][nj]) continue;
res += dfs(ni,nj);
}
}
return res;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j] && land[i][j] == 0) {
int ans = dfs(i,j);
res.push_back(ans);
}
}
}
sort(res.begin(), res.end());
return res;
}
};
python3代码如下,
class Solution:
def pondSizes(self, land: List[List[int]]) -> List[int]:
n, m = len(land), len(land[0])
st = [[False]*m for _ in range(n)]
res = []
def dfs(i: int, j: int) -> int:
st[i][j] = True
res = 1
for di in range(-1,2):
for dj in range(-1,2):
if di == 0 and dj == 0:
continue #去掉本身
ni = i + di
nj = j + dj
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if land[ni][nj] != 0:
continue
if st[ni][nj]:
continue
res += dfs(ni,nj)
return res
for i in range(n):
for j in range(m):
if not st[i][j] and land[i][j] == 0:
ans = dfs(i,j)
res.append(ans)
res.sort()
return res
题目5:LCS 03. 主题空间
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int largestArea(vector<string>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int res = 0;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int idx = 0; //给主题空间编号
vector<bool> is_nears; //该主题空间是否挨着走廊
function<int(int,int,char)> dfs =[&] (int i, int j, char c) -> int {
st[i][j] = true;
int res = 1;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
is_nears[idx] = true;
continue;
}
if (grid[ni][nj] != c) {
if (grid[ni][nj] == '0') {
is_nears[idx] = true;
}
continue;
}
if (st[ni][nj]) {
continue;
}
res += dfs(ni, nj, c);
}
return res;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j] && grid[i][j] != '0') {
is_nears.push_back(false);
int ans = dfs(i,j,grid[i][j]);
if (!is_nears[idx]) {
res = max(res, ans);
}
idx += 1; //主题空间编号加1
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def largestArea(self, grid: List[str]) -> int:
n = len(grid)
m = len(grid[0])
res = 0
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
st = [[False] * m for _ in range(n)]
idx = 0 #给每个主题空间编号
is_near = []
def dfs(i: int, j: int, c: str) -> int:
res = 1
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
is_near[idx] = True #这个主题空间挨着走廊
continue
if grid[ni][nj] != c:
if grid[ni][nj] == '0':
is_near[idx] = True #这个主题空间挨着走廊
continue
if st[ni][nj]:
continue
res += dfs(ni,nj,c)
return res
#计算答案
for i in range(n):
for j in range(m):
if grid[i][j] != '0' and not st[i][j]:
is_near.append(False)
ans = dfs(i,j,grid[i][j])
if not is_near[idx]:
res = max(res, ans)
idx += 1
return res
题目6:463. 岛屿的周长
解题思路:脑筋急转弯。遍历值为1的网格,遍历4个方向,如果与外面接边,则加1。
C++代码如下,
class Solution {
public:
int islandPerimeter(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
int res = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
res += 1;
continue;
}
if (grid[ni][nj] != 1) {
res += 1;
}
}
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
#脑筋急转弯
#遍历值为1的网格,遍历4个方向,如果与外面接边,则加1
n = len(grid)
m = len(grid[0])
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
res = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
res += 1
continue
if grid[ni][nj] != 1:
res += 1
continue
return res
题目7:2658. 网格图中鱼的最大数目
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int findMaxFish(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int res = 0;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
function<int(int,int)> dfs =[&] (int i, int j) -> int {
int res = grid[i][j];
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
continue;
}
if (grid[ni][nj] == 0) {
continue;
}
if (st[ni][nj]) {
continue;
}
res += dfs(ni,nj);
}
return res;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j] && grid[i][j] > 0) {
int ans = dfs(i, j);
res = max(res, ans);
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def findMaxFish(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
res = 0
st = [[False] * m for _ in range(n)]
def dfs(i: int, j: int) -> int:
res = grid[i][j]
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == 0:
continue
if st[ni][nj]:
continue
res += dfs(ni,nj)
return res
for i in range(n):
for j in range(m):
if not st[i][j] and grid[i][j] > 0:
ans = dfs(i,j)
res = max(res, ans)
return res
题目8:1034. 边界着色
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
set<pair<int,int>> coords;
function<void(int,int,int)> dfs =[&] (int i, int j, int target) -> void {
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
coords.insert(make_pair(i,j));
continue;
}
if (grid[ni][nj] != target) {
coords.insert(make_pair(i,j));
continue;
}
if (st[ni][nj]) {
continue;
}
dfs(ni,nj,target);
}
return;
};
dfs(row,col,grid[row][col]);
for (auto [i,j] : coords) {
grid[i][j] = color;
}
return grid;
}
};
python3代码如下,
class Solution:
def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
n, m = len(grid), len(grid[0])
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
coords = set()
def dfs(i: int, j: int, target: int) -> None:
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
coords.add((i,j))
continue
if grid[ni][nj] != target:
coords.add((i,j))
continue
if st[ni][nj]:
continue
dfs(ni,nj,target)
return
dfs(row,col,grid[row][col])
for i,j in coords:
grid[i][j] = color
return grid
题目9:1020. 飞地的数量
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int numEnclaves(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
int res = 0;
bool flag = false;
vector<vector<bool>> st(n, vector<bool>(m, false));
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
function<int(int,int)> dfs =[&] (int i, int j) -> int {
int res = 1;
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
flag = true;
continue;
}
if (grid[ni][nj] != 1) {
continue;
}
if (st[ni][nj]) {
continue;
}
res += dfs(ni,nj);
}
return res;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1 && !st[i][j]) {
flag = false;
int curr = dfs(i,j);
if (!flag) {
res += curr;
}
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def numEnclaves(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
flag = False
res = 0
def dfs(i: int, j: int) -> int:
nonlocal flag
res = 1
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
flag = True
continue
if grid[ni][nj] != 1:
continue
if st[ni][nj]:
continue
res += dfs(ni,nj)
return res
for i in range(n):
for j in range(m):
if grid[i][j] == 1 and not st[i][j]:
flag = False
ans = dfs(i, j)
if not flag:
res += ans
return res
题目10:2684. 矩阵中移动的最大次数
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int maxMoves(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<int>> d(n, vector<int>(m, -1));
int dirs[3][2] = {{-1,1},{0,1},{1,1}};
function<int(int,int)> dfs =[&] (int i, int j) -> int { //从(i,j)出发,能走到的最远距离
if (d[i][j] != -1) {
return d[i][j];
}
int res = 0;
for (int k = 0; k < 3; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[i][j] >= grid[ni][nj]) continue;
res = max(res, dfs(ni,nj)+1);
}
d[i][j] = res;
return res;
};
int res = 0;
for (int i = 0; i < n; ++i) {
int ans = dfs(i,0);
res = max(res, ans);
}
return res;
}
};
python3代码如下,
class Solution:
def maxMoves(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
d = [[-1] * m for _ in range(n)]
dirs = [[-1,1],[0,1],[1,1]]
def dfs(i: int, j: int) -> int: #从(i,j)出发,能走到的最远距离
nonlocal d
if d[i][j] != -1:
return d[i][j]
res = 0
for k in range(3):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[i][j] >= grid[ni][nj]:
continue
res = max(res, dfs(ni,nj)+1)
d[i][j] = res
return res
for i in range(n):
for j in range(m):
if d[i][j] == -1:
dfs(i,j)
res = 0
for i in range(n):
res = max(res, d[i][0]) #从矩阵的第1列单元格出发
return res
题目11:1254. 统计封闭岛屿的数目
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int closedIsland(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int res = 0;
bool flag = true;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
function<void(int,int)> dfs =[&] (int i, int j) -> void {
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
flag = false;
continue;
}
if (grid[ni][nj] != 0) {
continue;
}
if (st[ni][nj]) {
continue;
}
dfs(ni,nj);
}
return;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j] && grid[i][j] == 0) {
flag = true;
dfs(i,j);
if (flag) {
res += 1;
}
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def closedIsland(self, grid: List[List[int]]) -> int:
#把接触边界的岛屿去掉,剩下的岛屿个数,就是答案
n, m = len(grid), len(grid[0])
st = [[False] * m for _ in range(n)]
flag = True
res = 0
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
def dfs(i: int, j: int) -> None:
nonlocal flag
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
flag = False
continue
if grid[ni][nj] != 0:
continue
if st[ni][nj]:
continue
dfs(ni,nj)
return
for i in range(n):
for j in range(m):
if not st[i][j] and grid[i][j] == 0:
flag = True
dfs(i, j)
if flag:
res += 1
return res
题目12:130. 被围绕的区域
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
void solve(vector<vector<char>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
bool flag = true;
vector<pair<int,int>> coords;
function<void(int,int)> dfs =[&] (int i, int j) -> void {
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) {
flag = false;
continue;
}
if (grid[ni][nj] != 'O') {
continue;
}
if (st[ni][nj]) {
continue;
}
dfs(ni,nj);
}
return;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 'O' && !st[i][j]) {
flag = true;
dfs(i,j);
if (flag) {
coords.push_back(make_pair(i,j));
}
}
}
}
//处理coords
st = vector<vector<bool>>(n, vector<bool>(m, false));
function<void(int,int)> dfs1 =[&] (int i, int j) -> void {
st[i][j] = true;
grid[i][j] = 'X';
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] != 'O') continue;
if (st[ni][nj]) continue;
dfs1(ni,nj);
}
return;
};
for (auto [i,j] : coords) {
dfs1(i,j);
}
return;
}
};
python3代码如下,
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
n, m = len(board), len(board[0])
st = [[False] * m for _ in range(n)]
flag = True
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
coords = []
def dfs(i: int, j: int) -> None:
nonlocal flag
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
flag = False
continue
if board[ni][nj] != 'O':
continue
if st[ni][nj]:
continue
dfs(ni,nj)
return
for i in range(n):
for j in range(m):
if board[i][j] == 'O' and not st[i][j]:
flag = True
dfs(i,j)
if flag:
coords.append([i,j])
st = [[False] * m for _ in range(n)]
def dfs1(i: int, j: int) -> None:
st[i][j] = True
board[i][j] = 'X'
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if board[ni][nj] != 'O':
continue
if st[ni][nj]:
continue
dfs1(ni,nj) #记住,是dfs1
return
#print(f"coords = {coords}.")
#处理coords
for i,j in coords:
dfs1(i,j)
return
题目13:1905. 统计子岛屿
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
int n = grid2.size();
int m = grid2[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid2[i][j] == 1 && grid1[i][j] == 0) {
grid2[i][j] = 2;
}
}
}
int res = 0;
bool flag = true;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
function<void(int,int)> dfs =[&] (int i, int j) -> void {
st[i][j] = true;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid2[ni][nj] != 1) {
if (grid2[ni][nj] == 2) flag = false;
continue;
}
if (st[ni][nj]) continue;
dfs(ni,nj);
}
return;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid2[i][j] == 1 && !st[i][j]) {
flag = true;
dfs(i,j);
if (flag) {
res += 1;
}
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int:
n, m = len(grid2), len(grid2[0])
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
for i in range(n):
for j in range(m):
if grid2[i][j] == 1 and grid1[i][j] == 0:
grid2[i][j] = 2
res = 0
flag = True
def dfs(i: int, j: int) -> None:
nonlocal flag
st[i][j] = True
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid2[ni][nj] != 1:
if grid2[ni][nj] == 2:
flag = False
continue
if st[ni][nj]:
continue
dfs(ni,nj)
return
for i in range(n):
for j in range(m):
if grid2[i][j] == 1 and not st[i][j]:
flag = True
dfs(i,j)
if flag:
res += 1
return res
题目14:1391. 检查网格中是否存在有效路径
解题思路:dfs或者bfs。模拟。
C++代码如下,
class Solution {
public:
bool hasValidPath(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
function<bool(int,int,int,int)> check =[&] (int i, int j, int di, int dj) -> bool {
int ni = i + di;
int nj = j + dj;
if (ni < 0 || ni >= n || nj < 0 || nj >= m) return false;
if (st[ni][nj]) return false;
int nval = grid[ni][nj];
if (di == 0 && dj == -1) {
if (nval == 1 || nval == 4 || nval == 6) return true;
else return false;
} else if (di == 0 && dj == 1) {
if (nval == 1 || nval == 3 || nval == 5) return true;
else return false;
} else if (di == -1 && dj == 0) {
if (nval == 2 || nval == 3 || nval == 4) return true;
else return false;
} else if (di == 1 && dj == 0) {
if (nval == 2 || nval == 5 || nval == 6) return true;
else return false;
}
return false; //catch exception
};
queue<pair<int,int>> q;
q.push(make_pair(0,0));
st[0][0] = true;
while (!q.empty()) {
auto t = q.front();
q.pop();
int i = t.first;
int j = t.second;
if (i == n-1 && j == m-1) return true; //提前判断
int val = grid[i][j];
if (val == 1) {
if (check(i,j,0,-1)) {
q.push(make_pair(i,j-1));
st[i][j-1] = true;
}
if (check(i,j,0,1)) {
q.push(make_pair(i,j+1));
st[i][j+1] = true;
}
} else if (val == 2) {
if (check(i,j,-1,0)) {
q.push(make_pair(i-1,j));
st[i-1][j] = true;
}
if (check(i,j,1,0)) {
q.push(make_pair(i+1,j));
st[i+1][j] = true;
}
} else if (val == 3) {
if (check(i,j,0,-1)) {
q.push(make_pair(i,j-1));
st[i][j-1] = true;
}
if (check(i,j,1,0)) {
q.push(make_pair(i+1,j));
st[i+1][j] = true;
}
} else if (val == 4) {
if (check(i,j,0,1)) {
q.push(make_pair(i,j+1));
st[i][j+1] = true;
}
if (check(i,j,1,0)) {
q.push(make_pair(i+1,j));
st[i+1][j] = true;
}
} else if (val == 5) {
if (check(i,j,0,-1)) {
q.push(make_pair(i,j-1));
st[i][j-1] = true;
}
if (check(i,j,-1,0)) {
q.push(make_pair(i-1,j));
st[i-1][j] = true;
}
} else if (val == 6) {
if (check(i,j,-1,0)) {
q.push(make_pair(i-1,j));
st[i-1][j] = true;
}
if (check(i,j,0,1)) {
q.push(make_pair(i,j+1));
st[i][j+1] = true;
}
}
}
//坐标(i,j)
//val=1, [(i,j-1) nval=1,4,6] [(i,j+1) nval=1,3,5]
//val=2, [(i-1,j) nval=2,3,4] [(i+1,j) nval=2,5,6]
//val=3, [(i,j-1) nval=1,4,6] [(i+1,j) nval=2,5,6]
//val=4, [(i,j+1) nval=1,3,5] [(i+1,j) nval=2,5,6]
//val=5, [(i,j-1) nval=1,4,6] [(i-1,j) nval=2,3,4]
//val=6, [(i-1,j) nval=2,3,4] [(i,j+1) nval=1,3,5]
return false;
}
};
//递归深度过高,栈空间不足
class Solution {
public:
bool hasValidPath(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
function<bool(int,int,int,int)> check =[&] (int i, int j, int di, int dj) -> bool {
int ni = i + di;
int nj = j + dj;
if (ni < 0 || ni >= n || nj < 0 || nj >= m) return false;
if (st[ni][nj]) return false;
int nval = grid[ni][nj];
if (di == 0 && dj == -1) {
if (nval == 1 || nval == 4 || nval == 6) return true;
else return false;
} else if (di == 0 && dj == 1) {
if (nval == 1 || nval == 3 || nval == 5) return true;
else return false;
} else if (di == -1 && dj == 0) {
if (nval == 2 || nval == 3 || nval == 4) return true;
else return false;
} else if (di == 1 && dj == 0) {
if (nval == 2 || nval == 5 || nval == 6) return true;
else return false;
}
return false; //catch exception
};
//坐标(i,j)
//val=1, [(i,j-1) nval=1,4,6] [(i,j+1) nval=1,3,5]
//val=2, [(i-1,j) nval=2,3,4] [(i+1,j) nval=2,5,6]
//val=3, [(i,j-1) nval=1,4,6] [(i+1,j) nval=2,5,6]
//val=4, [(i,j+1) nval=1,3,5] [(i+1,j) nval=2,5,6]
//val=5, [(i,j-1) nval=1,4,6] [(i-1,j) nval=2,3,4]
//val=6, [(i-1,j) nval=2,3,4] [(i,j+1) nval=1,3,5]
function<bool(int,int)> dfs =[&] (int i, int j) -> bool {
if (i == n-1 && j == m-1) return true;
bool res = false;
st[i][j] = true;
int val = grid[i][j];
if (val == 1) {
if (check(i,j,0,-1)) res = res || dfs(i,j-1);
if (check(i,j,0,1)) res = res || dfs(i,j+1);
} else if (val == 2) {
if (check(i,j,-1,0)) res = res || dfs(i-1,j);
if (check(i,j,1,0)) res = res || dfs(i+1,j);
} else if (val == 3) {
if (check(i,j,0,-1)) res = res || dfs(i,j-1);
if (check(i,j,1,0)) res = res || dfs(i+1,j);
} else if (val == 4) {
if (check(i,j,0,1)) res = res || dfs(i,j+1);
if (check(i,j,1,0)) res = res || dfs(i+1,j);
} else if (val == 5) {
if (check(i,j,0,-1)) res = res || dfs(i,j-1);
if (check(i,j,-1,0)) res = res || dfs(i-1,j);
} else if (val == 6) {
if (check(i,j,-1,0)) res = res || dfs(i-1,j);
if (check(i,j,0,1)) res = res || dfs(i,j+1);
}
return res;
};
return dfs(0,0);
}
};
python3代码如下,
class Solution:
def hasValidPath(self, grid: List[List[int]]) -> bool:
n, m = len(grid), len(grid[0])
st = [[False] * m for _ in range(n)]
#坐标(i,j)
#val=1, [(i,j-1) nval=1,4,6] [(i,j+1) nval=1,3,5]
#val=2, [(i-1,j) nval=2,3,4] [(i+1,j) nval=2,5,6]
#val=3, [(i,j-1) nval=1,4,6] [(i+1,j) nval=2,5,6]
#val=4, [(i,j+1) nval=1,3,5] [(i+1,j) nval=2,5,6]
#val=5, [(i,j-1) nval=1,4,6] [(i-1,j) nval=2,3,4]
#val=6, [(i-1,j) nval=2,3,4] [(i,j+1) nval=1,3,5]
def check(i: int, j: int, di: int, dj: int) -> bool:
ni = i + di
nj = j + dj
if ni < 0 or ni >= n or nj < 0 or nj >= m:
return False
if st[ni][nj]:
return False
nval = grid[ni][nj]
if di == 0 and dj == -1 and (nval not in [1,4,6]):
return False
if di == 0 and dj == 1 and (nval not in [1,3,5]):
return False
if di == -1 and dj == 0 and (nval not in [2,3,4]):
return False
if di == 1 and dj == 0 and (nval not in [2,5,6]):
return False
return True
def dfs(i: int, j: int) -> bool:
#print(f"dfs, i = {i}, j = {j}.")
if i == n-1 and j == m-1:
return True
st[i][j] = True
val = grid[i][j]
res = False
if val == 1:
if check(i,j,0,-1):
res = res or dfs(i,j-1)
if check(i,j,0,1):
res = res or dfs(i,j+1)
elif val == 2:
if check(i,j,-1,0):
res = res or dfs(i-1,j)
if check(i,j,1,0):
res = res or dfs(i+1,j)
elif val == 3:
if check(i,j,0,-1):
res = res or dfs(i,j-1)
if check(i,j,1,0):
res = res or dfs(i+1,j)
elif val == 4:
if check(i,j,0,1):
res = res or dfs(i,j+1)
if check(i,j,1,0):
res = res or dfs(i+1,j)
elif val == 5:
if check(i,j,0,-1):
res = res or dfs(i,j-1)
if check(i,j,-1,0):
res = res or dfs(i-1,j)
elif val == 6:
if check(i,j,-1,0):
res = res or dfs(i-1,j)
if check(i,j,0,1):
res = res or dfs(i,j+1)
return res
return dfs(0,0)
题目15:417. 太平洋大西洋水流问题
解题思路:bfs或者dfs。
C++代码如下,
class Solution {
public:
vector<vector<int>> pacificAtlantic(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
vector<vector<bool>> st1(n, vector<bool>(m, false));
vector<vector<bool>> st2(n, vector<bool>(m, false));
queue<pair<int,int>> q;
for (int i = 0; i < n; ++i) {
q.push(make_pair(i,0));
st1[i][0] = true;
}
for (int j = 1; j < m; ++j) {
q.push(make_pair(0,j));
st1[0][j] = true;
}
function<void(queue<pair<int,int>>&,vector<vector<bool>>&)> bfs =[&] (queue<pair<int,int>>& q, vector<vector<bool>>& st) -> void {
while (!q.empty()) {
auto t = q.front();
q.pop();
int i = t.first;
int j = t.second;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (st[ni][nj]) continue;
if (grid[ni][nj] < grid[i][j]) continue; //往高处走
st[ni][nj] = true;
q.push(make_pair(ni,nj));
}
}
return;
};
bfs(q, st1);
q = queue<pair<int,int>>();
for (int i = 0; i < n; ++i) {
q.push(make_pair(i,m-1));
st2[i][m-1] = true;
}
for (int j = 0; j < m-1; ++j) {
q.push(make_pair(n-1,j));
st2[n-1][j] = true;
}
bfs(q, st2);
vector<vector<int>> res;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (st1[i][j] && st2[i][j]) {
vector<int> t = {i,j};
res.push_back(t);
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def pacificAtlantic(self, grid: List[List[int]]) -> List[List[int]]:
n, m = len(grid), len(grid[0])
st1 = [[False] * m for _ in range(n)]
st2 = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
def bfs(q, st) -> None:
while len(q) > 0:
i, j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if st[ni][nj]:
continue
if grid[i][j] > grid[ni][nj]: #往高处走
continue
q.append([ni,nj])
st[ni][nj] = True
return
q = collections.deque([])
for i in range(n):
q.append([i,0])
st1[i][0] = True
for j in range(1,m):
q.append([0,j])
st1[0][j] = True
bfs(q,st1)
q = collections.deque([])
for i in range(n):
q.append([i,m-1])
st2[i][m-1] = True
for j in range(0,m-1):
q.append([n-1,j])
st2[n-1][j] = True
bfs(q,st2)
res = []
for i in range(n):
for j in range(m):
if st1[i][j] and st2[i][j]:
res.append([i,j])
return res
题目16:529. 扫雷游戏
解题思路:dfs或者bfs。
C++代码如下,
class Solution {
public:
vector<vector<char>> updateBoard(vector<vector<char>>& grid, vector<int>& click) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int dirs[8][2] = {{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
queue<pair<int,int>> q;
int si = click[0];
int sj = click[1];
if (grid[si][sj] == 'M') { //特判
grid[si][sj] = 'X';
return grid;
}
q.push(make_pair(si,sj));
st[si][sj] = true;
while (!q.empty()) {
auto t = q.front();
int i = t.first;
int j = t.second;
q.pop();
vector<pair<int,int>> coords;
int cnt = 0; //相邻的地雷数目
for (int k = 0; k < 8; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (st[ni][nj]) continue;
if (grid[ni][nj] != 'E') {
if (grid[ni][nj] == 'M') {
cnt += 1;
}
continue;
}
coords.push_back(make_pair(ni,nj));
}
if (cnt == 0) {
grid[i][j] = 'B';
for (auto [ni, nj] : coords) {
q.push(make_pair(ni,nj));
st[ni][nj] = true;
}
} else {
//cnt > 0
string str_cnt = to_string(cnt);
grid[i][j] = str_cnt[0];
}
}
return grid;
}
};
python3代码如下,
class Solution:
def updateBoard(self, grid: List[List[str]], click: List[int]) -> List[List[str]]:
n, m = len(grid), len(grid[0])
si, sj = click
st = [[False] * m for _ in range(n)]
q = collections.deque([])
if grid[si][sj] == 'M': #特判
grid[si][sj] = 'X'
return grid
dirs = [[-1,0],[1,0],[0,-1],[0,1],[-1,-1],[-1,1],[1,-1],[1,1]]
q.append([si,sj])
st[si][sj] = True
while len(q) > 0:
i, j = q.popleft()
cnt = 0 #8邻域内的地雷数目
coords = []
for k in range(8):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] != 'E':
if grid[ni][nj] == 'M':
cnt += 1
continue
if st[ni][nj]:
continue
coords.append([ni,nj])
if cnt == 0:
grid[i][j] = 'B'
for ni,nj in coords:
q.append([ni,nj])
st[ni][nj] = True
else: #cnt>0
grid[i][j] = str(cnt)
return grid
题目17:1559. 二维网格图中探测环
解题思路:点(i,j)
四邻域扩展时,if st[ni][nj]
判断放在最后,如果进入到这个分支2次,则说明存在环。
C++代码如下,
class Solution {
public:
bool containsCycle(vector<vector<char>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
function<bool(int,int)> bfs =[&] (int i, int j) -> bool {
queue<pair<int,int>> q;
char target = grid[i][j];
q.push(make_pair(i,j));
st[i][j] = true;
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
int cnt = 0;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] != target) continue;
if (st[ni][nj]) {
cnt += 1;
continue;
}
q.push(make_pair(ni,nj));
st[ni][nj] = true;
}
if (cnt >= 2) return true;
}
return false;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (!st[i][j]) {
if (bfs(i,j)) return true;
}
}
}
return false;
}
};
python3代码如下,
class Solution:
def containsCycle(self, grid: List[List[str]]) -> bool:
#怎么判断形成了环呢?
#点(i,j)四邻域扩展时,if st[ni][nj]判断放在最后,如果进入到这个分支2次,则说明存在环
n, m = len(grid), len(grid[0])
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
def bfs(i: int, j: int) -> bool:
target = grid[i][j]
q = collections.deque([])
q.append([i,j])
st[i][j] = True
while len(q) > 0:
i, j = q.popleft()
cnt = 0
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] != target:
continue
if st[ni][nj]:
cnt += 1
continue
q.append([ni,nj])
st[ni][nj] = True
if cnt >= 2:
return True
return False
for i in range(n):
for j in range(m):
if not st[i][j]:
if bfs(i,j):
return True
return False
题目18:827. 最大人工岛
解题思路:先计算(i,j)
位置处的岛屿编号idx
,并计数该编号idx
的岛屿大小。然后遍历每个grid[i][j] == 0
的位置(i,j)
,四邻域扩展,去重,累计岛屿大小,更新答案。
C++代码如下,
class Solution {
public:
int largestIsland(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int idx = 0; //岛屿的编号
vector<int> cnt; //岛屿的大小
vector<vector<int>> island_idx(n, vector<int>(m, -1)); //(i,j)属于哪一个岛屿
function<vector<pair<int,int>>(int,int)> bfs =[&] (int si, int sj) -> vector<pair<int,int>> {
vector<pair<int,int>> res;
queue<pair<int,int>> q;
q.push(make_pair(si,sj));
st[si][sj] = true;
res.push_back(make_pair(si,sj));
while (!q.empty()) {
auto t = q.front();
q.pop();
int i = t.first;
int j = t.second;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] != 1) continue;
if (st[ni][nj]) continue;
q.push(make_pair(ni,nj));
st[ni][nj] = true;
res.push_back(make_pair(ni,nj));
}
}
return res;
};
int res = 0; //计算答案
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1 && !st[i][j]) {
vector<pair<int,int>> coords = bfs(i,j);
int num = coords.size();
for (auto [ni, nj] : coords) {
island_idx[ni][nj] = idx;
}
cnt.push_back(num);
res = max(res, num);
idx += 1;
}
}
}
//计算答案
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 0) {
int curr = 1;
set<int> visited;
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] != 1) continue;
int idx = island_idx[ni][nj];
if (visited.find(idx) != visited.end()) continue;
int num = cnt[idx];
curr += num;
visited.insert(idx);
}
res = max(res, curr);
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def largestIsland(self, grid: List[List[int]]) -> int:
n = len(grid)
m = len(grid)
island_idx = [[0] * m for _ in range(n)] #(i,j)所在岛屿的编号
cnt = [] #编号为i的岛屿的大小为cnt[i]
idx = 0
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
def bfs(si: int, sj: int) -> list:
res = []
q = collections.deque([])
q.append([si,sj])
st[si][sj] = True
res.append([si,sj])
while len(q) > 0:
i, j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] != 1:
continue
if st[ni][nj]:
continue
q.append([ni,nj])
st[ni][nj] = True
res.append([ni,nj])
return res
#每个位置(i,j)至多遍历2次,则时间复杂度为O(2*n*m)
res = 0 #计算答案
for i in range(n):
for j in range(m):
if grid[i][j] == 1 and not st[i][j]:
coords = bfs(i,j)
num = len(coords)
res = max(res, num)
for ni, nj in coords:
island_idx[ni][nj] = idx
cnt.append(num)
idx += 1
for i in range(n):
for j in range(m):
if grid[i][j] == 0:
curr = 1
visited = set()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == 0:
continue
idx = island_idx[ni][nj]
if idx in visited:
continue
curr += cnt[idx]
visited.add(idx)
res = max(res, curr)
return res
题目19:LCP 63. 弹珠游戏
解题思路:起点(si,sj)
以及方向sz
,那么路径就固定死了,不会分叉。
C++代码如下,
class Solution {
public:
vector<vector<int>> ballGame(int limit, vector<string>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
vector<vector<int>> snodes; //起点
for (int i = 1; i < n-1; ++i) {
if (grid[i][0] == '.') {
vector<int> t = {i, 0, 3};
snodes.push_back(t);
}
if (grid[i][m-1] == '.') {
vector<int> t = {i, m-1, 1};
snodes.push_back(t);
}
}
for (int j = 1; j < m-1; ++j) {
if (grid[0][j] == '.') {
vector<int> t = {0,j,2};
snodes.push_back(t);
}
if (grid[n-1][j] == '.') {
vector<int> t = {n-1,j,0};
snodes.push_back(t);
}
}
function<bool(vector<int>)> check =[&] (vector<int> node) -> bool {
int level = limit;
while (level--) {
int i = node[0];
int j = node[1];
int z = node[2];
int ni = i + dirs[z][0];
int nj = j + dirs[z][1];
int nz = -1;
if (ni < 0 || ni >= n || nj < 0 || nj >= m) return false;
if (grid[ni][nj] == '.') {
nz = z;
} else if (grid[ni][nj] == 'E') {
nz = (z-1+4)%4;
} else if (grid[ni][nj] == 'W') {
nz = (z+1)%4;
} else if (grid[ni][nj] == 'O') {
return true;
}
vector<int> t = {ni,nj,nz};
node = t; //更新node
}
return false;
};
//计算答案
vector<vector<int>> res;
for (auto snode : snodes) {
if (check(snode)) {
res.push_back({snode[0],snode[1]});
}
}
sort(res.begin(), res.end());
return res;
}
};
python3代码如下,
class Solution:
def ballGame(self, limit: int, grid):
#状态(i,j,z)表示网格(i,j),以及进入网格(i,j)的方向z
#z=0,(dx,dy)=(-1,0)
#z=1,(dx,dy)=(0,-1)
#z=2,(dx,dy)=(1,0)
#z=3,(dx,dy)=(0,1)
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
n = len(grid)
m = len(grid[0])
snodes = []
for i in range(1,n-1):
if grid[i][0] == '.':
snodes.append([i,0,3])
if grid[i][m-1] == '.':
snodes.append([i,m-1,1])
for j in range(1,m-1):
if grid[0][j] == '.':
snodes.append([0,j,2])
if grid[n-1][j] == '.':
snodes.append([n-1,j,0])
def bfs(snode: list) -> bool:
si, sj, sz = snode #起点(si,sj)以及方向sz,那么路径就固定死了,不会分叉
level = limit
while level > 0:
level -= 1
i, j, z = snode
ni = i + dirs[z][0]
nj = j + dirs[z][1]
nz = -1
if ni < 0 or ni >= n or nj < 0 or nj >= m: #走到头了
return False
#计算进入网格(ni,nj)的方向
if grid[ni][nj] == '.':
nz = z
elif grid[ni][nj] == 'E':
nz = (z-1+4) % 4
else:
#'W'
nz = (z+1) % 4
snode = (ni,nj,nz) #更新snode
if grid[ni][nj] == 'O':
return True
return False
res = []
#遍历起点,感觉会超时
for snode in snodes:
if bfs(snode):
res.append([snode[0],snode[1]])
return res
#队列超时
#从终点反向bfs也超时了
class Solution:
def ballGame(self, limit: int, grid):
#状态(i,j,z)表示网格(i,j),以及进入网格(i,j)的方向z
#z=0,(dx,dy)=(-1,0)
#z=1,(dx,dy)=(0,-1)
#z=2,(dx,dy)=(1,0)
#z=3,(dx,dy)=(0,1)
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
n = len(grid)
m = len(grid[0])
res = [] #答案
#从终点开始遍历
q = collections.deque([])
st = [[[False] * 4 for _ in range(m)] for _ in range(n)]
for i in range(n):
for j in range(m):
if grid[i][j] == 'O':
for k in range(4):
q.append([i,j,k])
st[i][j][k] = True
level = 0
while len(q) > 0:
tot = len(q)
while tot:
tot -= 1 #更新tot
i,j,z = q.popleft()
ni = i + dirs[z][0]
nj = j + dirs[z][1]
nz = -1
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == 'O':
continue
if grid[ni][nj] == '.':
nz = z
elif grid[ni][nj] == 'E':
nz = (z+1)%4
elif grid[ni][nj] == 'W':
nz = (z-1+4)%4
if st[ni][nj][nz]:
continue
q.append([ni,nj,nz])
st[ni][nj][nz] = True
#保存答案
if grid[ni][nj] == '.':
if nj == 0 and 1 <= ni <= n-2 and nz == 1:
res.append([ni,nj])
if nj == m-1 and 1 <= ni <= n-2 and nz == 3:
res.append([ni,nj])
if ni == 0 and 1 <= nj <= m-2 and nz == 0:
res.append([ni,nj])
if ni == n-1 and 1 <= nj <= m-2 and nz == 2:
res.append([ni,nj])
level += 1
if level >= limit: #最多运行走limit步
break
res.sort()
return res
#队列超时
#从起点遍历会超时
class Solution:
def ballGame(self, limit: int, grid):
#状态(i,j,z)表示网格(i,j),以及进入网格(i,j)的方向z
#z=0,(dx,dy)=(-1,0)
#z=1,(dx,dy)=(0,-1)
#z=2,(dx,dy)=(1,0)
#z=3,(dx,dy)=(0,1)
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
n = len(grid)
m = len(grid[0])
snodes = []
for i in range(1,n-1):
if grid[i][0] == '.':
snodes.append([i,0,3])
if grid[i][m-1] == '.':
snodes.append([i,m-1,1])
for j in range(1,m-1):
if grid[0][j] == '.':
snodes.append([0,j,2])
if grid[n-1][j] == '.':
snodes.append([n-1,j,0])
def bfs(snode: list) -> bool:
si, sj, sz = snode
q = collections.deque([])
st = [[[False] * 4 for _ in range(m)] for _ in range(n)]
st[si][sj][sz] = True
q.append([si,sj,sz])
level = 0
while len(q) > 0:
i, j, z = q.popleft()
ni = i + dirs[z][0]
nj = j + dirs[z][1]
nz = -1
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
#计算进入网格(ni,nj)的方向
if grid[ni][nj] == '.':
nz = z
elif grid[ni][nj] == 'E':
nz = (z-1+4) % 4
else:
#'W'
nz = (z+1) % 4
if st[ni][nj][nz]:
continue
q.append([ni,nj,nz])
st[ni][nj][nz] = True
if grid[ni][nj] == 'O':
return True
level += 1
if level >= limit:
break
return False
res = []
#遍历起点,感觉会超时
for snode in snodes:
if bfs(snode):
res.append([snode[0],snode[1]])
return res
2.3 BFS(求最短路)
题目20:1926. 迷宫中离入口最近的出口
解题思路:最短路,bfs。
C++代码如下,
class Solution {
public:
int nearestExit(vector<vector<char>>& grid, vector<int>& snode) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
queue<pair<int,int>> q;
q.push(make_pair(snode[0],snode[1]));
st[snode[0]][snode[1]] = true;
int dirs[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
int level = 0;
while (!q.empty()) {
level += 1;
int tot = q.size();
while (tot--) {
auto [i, j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (st[ni][nj]) continue;
if (grid[ni][nj] == '+') continue;
q.push(make_pair(ni,nj));
st[ni][nj] = true;
if (ni == 0 || ni == n-1 || nj == 0 || nj == m-1) {
return level;
}
}
}
}
return -1;
}
};
python3代码如下,
class Solution:
def nearestExit(self, grid: List[List[str]], entrance: List[int]) -> int:
n, m = len(grid), len(grid[0])
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
st = [[False] * m for _ in range(n)]
q = collections.deque([])
q.append(entrance)
st[entrance[0]][entrance[1]] = True
level = 0
while len(q) > 0:
level += 1
tot = len(q)
while tot > 0:
tot -= 1
i,j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == '+':
continue
if st[ni][nj]:
continue
q.append([ni,nj])
st[ni][nj] = True
if ni == 0 or ni == n-1 or nj == 0 or nj == m-1:
return level
return -1
题目21:1091. 二进制矩阵中的最短路径
解题思路:bfs。
C++代码如下,
class Solution {
public:
int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[8][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}, {-1,-1}, {-1,1}, {1,-1}, {1,1}};
vector<vector<bool>> st(n, vector<bool>(m, false));
if (grid[0][0] == 1 || grid[n-1][m-1] == 1) { //特判
return -1;
}
queue<pair<int,int>> q;
q.push(make_pair(0,0));
st[0][0] = true;
int level = 1;
while (!q.empty()) {
int tot = q.size();
while (tot--) {
auto [i,j] = q.front();
q.pop();
if (i == n-1 && j == m-1) { //提前判断
return level;
}
for (int k = 0; k < 8; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] != 0) continue;
if (st[ni][nj]) continue;
q.push(make_pair(ni,nj));
st[ni][nj] = true;
}
}
level += 1;
}
return -1;
}
};
python3代码如下,
class Solution:
def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
n = len(grid)
m = len(grid[0])
if grid[0][0] == 1 or grid[n-1][m-1] == 1: #特判
return -1
dirs = [[-1,0],[1,0],[0,-1],[0,1],[-1,-1],[-1,1],[1,-1],[1,1]]
st = [[False] * m for _ in range(n)]
level = 1
q = collections.deque([])
q.append([0,0])
st[0][0] = True
while len(q) > 0:
tot = len(q)
while tot > 0:
tot -= 1
i,j = q.popleft()
if i == n-1 and j == m-1: #提前判断
return level
for k in range(8):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] != 0:
continue
if st[ni][nj]:
continue
q.append([ni,nj])
st[ni][nj] = True
level += 1
return -1
题目22:1162. 地图分析
解题思路:bfs。
C++代码如下,
class Solution {
public:
int maxDistance(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<int>> d(n, vector<int>(m, -1));
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
queue<pair<int,int>> q;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
q.push(make_pair(i,j));
d[i][j] = 0;
}
}
}
if (q.size() == 0 || q.size() == n*m) { //特判
return -1;
}
int res = -1;
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (d[ni][nj] != -1) continue;
q.push(make_pair(ni,nj));
d[ni][nj] = d[i][j] + 1;
res = max(res, d[ni][nj]);
}
}
return res;
}
};
python3代码如下,
class Solution:
def maxDistance(self, grid: List[List[int]]) -> int:
n = len(grid)
m = len(grid[0])
d = [[-1] * m for _ in range(n)]
st = [[False] * m for _ in range(n)]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
q = collections.deque([])
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
q.append([i,j])
st[i][j] = True
d[i][j] = 0
if len(q) == 0 or len(q) == n*m: #特判全是海洋或者陆地的情况
return -1
res = -1
while len(q) > 0:
i, j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if st[ni][nj]:
continue
d[ni][nj] = d[i][j] + 1
q.append([ni,nj])
res = max(res, d[ni][nj])
st[ni][nj] = True
return res
题目23:542. 01 矩阵
解题思路:bfs。
C++代码如下,
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<int>> d(n, vector<int>(m, -1));
queue<pair<int,int>> q;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 0) {
q.push(make_pair(i,j));
d[i][j] = 0;
}
}
}
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (d[ni][nj] != -1) continue;
q.push(make_pair(ni,nj));
d[ni][nj] = d[i][j] + 1;
}
}
return d;
}
};
python3代码如下,
class Solution:
def updateMatrix(self, grid: List[List[int]]) -> List[List[int]]:
n = len(grid)
m = len(grid[0])
d = [[-1] * m for _ in range(n)]
q = collections.deque([])
for i in range(n):
for j in range(m):
if grid[i][j] == 0:
q.append([i,j])
d[i][j] = 0
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
while len(q) > 0:
i,j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if d[ni][nj] != -1:
continue
q.append([ni,nj])
d[ni][nj] = d[i][j] + 1
return d
题目24:994. 腐烂的橘子
解题思路:bfs。
C++代码如下,
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
queue<pair<int,int>> q;
int cnt = 0; //初始时,新鲜橘子的数量
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 2) {
q.push(make_pair(i,j));
} else if (grid[i][j] == 1) {
cnt += 1;
}
}
}
if (cnt == 0) { //特判没有新鲜橘子的情况
return 0;
}
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int level = 0;
while (!q.empty()) {
int tot = q.size();
while (tot--) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] == 1) {
q.push(make_pair(ni,nj));
grid[ni][nj] = 2;
}
}
}
level += 1;
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) { //特判还有新鲜橘子剩余的情况
return -1;
}
}
}
return level-1;
}
};
python3代码如下,
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
q = collections.deque([])
cnt = 0 #新鲜橘子的个数
for i in range(n):
for j in range(m):
if grid[i][j] == 2:
q.append([i,j])
elif grid[i][j] == 1:
cnt += 1
if cnt == 0: #特判初始就没有新鲜橘子
return 0
level = 0
while len(q) > 0:
tot = len(q)
while tot > 0:
tot -= 1
i,j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == 1:
q.append([ni,nj])
grid[ni][nj] = 2
level += 1
for i in range(n):
for j in range(m):
if grid[i][j] == 1: #特判还有橘子剩余
return -1
return level-1
题目25:1765. 地图中的最高点
解题思路:bfs。
C++代码如下,
class Solution {
public:
vector<vector<int>> highestPeak(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
vector<vector<bool>> st(n, vector<bool>(m, false));
queue<pair<int,int>> q;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
q.push(make_pair(i,j));
st[i][j] = true;
grid[i][j] = 0;
}
}
}
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (st[ni][nj]) continue;
q.push(make_pair(ni,nj));
st[ni][nj] = true;
grid[ni][nj] = grid[i][j] + 1;
}
}
return grid;
}
};
python3代码如下,
class Solution:
def highestPeak(self, grid: List[List[int]]) -> List[List[int]]:
n = len(grid)
m = len(grid[0])
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
st = [[False] * m for _ in range(n)]
q = collections.deque([])
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
q.append([i,j])
st[i][j] = True
grid[i][j] = 0
while len(q) > 0:
i,j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if st[ni][nj]:
continue
q.append([ni,nj])
st[ni][nj] = True
grid[ni][nj] = grid[i][j] + 1
return grid
题目26:934. 最短的桥
解题思路:两遍bfs。
C++代码如下,
class Solution {
public:
int shortestBridge(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
vector<vector<bool>> st(n, vector<bool>(m, false));
vector<vector<pair<int,int>>> coords_vec; //coords_vec[0]表示岛屿0的坐标
function<vector<pair<int,int>>(int,int)> bfs =[&] (int i, int j) -> vector<pair<int,int>> {
vector<pair<int,int>> res;
queue<pair<int,int>> q;
q.push(make_pair(i,j));
st[i][j] = true;
res.push_back(make_pair(i,j));
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] != 1) continue;
if (st[ni][nj]) continue;
q.push(make_pair(ni,nj));
st[ni][nj] = true;
res.push_back(make_pair(ni,nj));
}
}
return res;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1 && !st[i][j]) {
vector<pair<int,int>> coords = bfs(i,j);
coords_vec.push_back(coords);
}
}
}
//计算岛屿到水域的距离
vector<vector<int>> d0(n, vector<int>(m, -1));
vector<vector<int>> d1(n, vector<int>(m, -1));
function<void(vector<pair<int,int>>,vector<vector<int>>&)> compute_d =[&] (vector<pair<int,int>> snodes, vector<vector<int>>& d) -> void {
queue<pair<int,int>> q;
for (auto [si,sj] : snodes) {
q.push(make_pair(si,sj));
d[si][sj] = 0;
}
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (d[ni][nj] != -1) continue;
if (grid[ni][nj] != 0) continue;
q.push(make_pair(ni,nj));
d[ni][nj] = d[i][j] + 1;
}
}
return;
};
compute_d(coords_vec[0], d0);
compute_d(coords_vec[1], d1);
//计算答案
int res = n * m;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 0 && d0[i][j] > 0 && d1[i][j] > 0) {
int curr = d0[i][j] + d1[i][j] - 1;
res = min(res, curr);
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def shortestBridge(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
d0 = [[-1] * m for _ in range(n)] #编号为0的岛屿到水域的距离
d1 = [[-1] * m for _ in range(n)] #编号为1的岛屿到水域的距离
def bfs(i: int, j: int) -> None:
res = []
q = collections.deque([])
q.append([i,j])
st[i][j] = True
res.append([i,j])
while len(q) > 0:
i,j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if st[ni][nj]:
continue
if grid[ni][nj] != 1:
continue
q.append([ni,nj])
st[ni][nj] = True
res.append([ni,nj])
return res
coords_vec = []
st = [[False] * m for _ in range(n)]
for i in range(n):
for j in range(m):
if grid[i][j] == 1 and not st[i][j]:
coords = bfs(i,j) #(i,j)所在岛屿的所有坐标
coords_vec.append(coords)
def compute_d(snodes: list, d: list) -> None:
q = collections.deque([])
for snode in snodes:
q.append(snode)
d[snode[0]][snode[1]] = 0
while len(q) > 0:
i, j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if grid[ni][nj] == 1:
continue
if d[ni][nj] != -1:
continue
q.append([ni,nj])
d[ni][nj] = d[i][j] + 1
return
compute_d(coords_vec[0], d0)
compute_d(coords_vec[1], d1)
res = n + m
for i in range(n):
for j in range(m):
if grid[i][j] == 0 and d0[i][j] > 0 and d1[i][j] > 0:
curr = d0[i][j] + d1[i][j] - 1
res = min(res, curr)
return res
解题思路:bfs。
C++代码如下,
class Solution {
public:
vector<vector<int>> highestRankedKItems(vector<vector<int>>& grid, vector<int>& pricing, vector<int>& start, int topk) {
int n = grid.size();
int m = grid[0].size();
int dirs[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
vector<vector<int>> d(n, vector<int>(m, -1));
queue<pair<int,int>> q;
q.push(make_pair(start[0],start[1]));
d[start[0]][start[1]] = 0;
while (!q.empty()) {
auto [i,j] = q.front();
q.pop();
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
if (grid[ni][nj] == 0) continue;
if (d[ni][nj] != -1) continue;
q.push(make_pair(ni,nj));
d[ni][nj] = d[i][j] + 1;
}
}
// //输出数组d
// for (int i = 0; i < n; ++i) {
// for (int j = 0; j < m; ++j) {
// cout << d[i][j] << ",";
// }
// cout << endl;
// }
//计算答案
vector<vector<int>> res;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int x = grid[i][j];
if (x > 1 && pricing[0] <= x && x <= pricing[1] && d[i][j] != -1) {
vector<int> t = {d[i][j], x, i, j};
res.push_back(t);
}
}
}
sort(res.begin(), res.end());
// //输出res数组
// for (int i = 0; i < res.size(); ++i) {
// for (int j = 0; j < res[i].size(); ++j) {
// cout << res[i][j] << ",";
// }
// cout << endl;
// }
vector<vector<int>> real_res;
for (int i = 0; i < min(topk, (int)res.size()); ++i) {
real_res.push_back({res[i][2],res[i][3]});
}
return real_res;
}
};
python3代码如下,
class Solution:
def highestRankedKItems(self, grid: List[List[int]], pricing: List[int], start: List[int], topk: int) -> List[List[int]]:
n, m = len(grid), len(grid[0])
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
d = [[-1] * m for _ in range(n)]
q = collections.deque([start])
d[start[0]][start[1]] = 0
while len(q) > 0:
i, j = q.popleft()
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
if d[ni][nj] != -1:
continue
if grid[ni][nj] == 0:
continue
q.append([ni,nj])
d[ni][nj] = d[i][j] + 1
#计算答案
res = []
for i in range(n):
for j in range(m):
if grid[i][j] != 1 and pricing[0] <= grid[i][j] <= pricing[1] and d[i][j] != -1:
res.append([d[i][j],grid[i][j],i,j])
res.sort()
real_res = []
for a,b,c,d in res:
real_res.append([c,d])
if len(real_res) <= topk:
return real_res
else:
return real_res[0:topk]
题目28:1293. 网格中的最短路径
解题思路:直接bfs,只不过多了一个状态位,表示剩余可经过的障碍物个数。
C++代码如下,
class Solution {
public:
int shortestPath(vector<vector<int>>& grid, int maxk) {
int n = grid.size();
int m = grid[0].size();
if (n+m-3 <= maxk) { //特判比较可消除障碍物比较充裕的情况
return n+m-2;
}
int dirs[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
vector<vector<vector<bool>>> st(n,vector<vector<bool>>(m, vector<bool>(maxk+1,false)));
queue<vector<int>> q;
q.push({0,0,maxk});
st[0][0][maxk] = true;
int level = 0;
while (!q.empty()) {
int tot = q.size();
while (tot--) {
auto t = q.front();
q.pop();
int i = t[0];
int j = t[1];
int z = t[2];
if (i == n-1 && j == m-1) { //提前返回
return level;
}
for (int k = 0; k < 4; ++k) {
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
int nz = z - grid[ni][nj];
if (nz < 0) continue;
if (st[ni][nj][nz]) continue;
q.push({ni,nj,nz});
st[ni][nj][nz] = true;
}
}
level += 1;
}
return -1;
}
};
python3代码如下,
class Solution:
def shortestPath(self, grid: List[List[int]], topk: int) -> int:
#直接bfs,只不过多了一个状态位,表示剩余可经过的障碍物个数
n, m = len(grid), len(grid[0])
if topk >= (n+m-1)-2: #特判可消除的障碍物比较多的情况
#总共n+m-1个点,去掉终点和起点,有n+m-3个点
#n+m-1个点,需要n+m-2步
return n+m-2
dirs = [[-1,0],[0,-1],[1,0],[0,1]]
st = [[[False] * (topk+1) for _ in range(m)] for _ in range(n)]
q = collections.deque([])
q.append([0,0,topk])
st[0][0][topk] = True
level = 0
while len(q) > 0:
tot = len(q)
while tot > 0:
tot -= 1
i, j, z = q.popleft()
if i == n-1 and j == m-1: #提前返回
return level
for k in range(4):
ni = i + dirs[k][0]
nj = j + dirs[k][1]
if ni < 0 or ni >= n or nj < 0 or nj >= m:
continue
nz = z - grid[ni][nj]
if nz < 0:
continue
if st[ni][nj][nz]:
continue
q.append([ni,nj,nz])
st[ni][nj][nz] = True
level += 1
return -1