灵神力扣题单之网格图(上)

17 阅读44分钟

1 介绍

本博客用来记录灵神力扣题单之网格图

2 训练

2.1 例题

题目11210. 穿过迷宫的最少移动次数

解题思路:bfs。模拟。状态表示为(x,y,s)表示蛇尾在(x,y)位置处,s=0表示水平方向,s=1表示竖直方向。无论水平方向还是竖直方向,

(1)向下移动:x增加1,y和s不变。用三元组(1,0,0)表示。前两个元素是加,后一个元素是异或。

(2)向右移动:y增加1,xs不变。用三元组(0,1,0)表示。

(3)旋转:s切换,即0变为11变为0xy不变。用三元组(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

题目2200. 岛屿数量

解题思路: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 
        

题目3695. 岛屿的最大面积

解题思路: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 

题目5LCS 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 

题目6463. 岛屿的周长

解题思路:脑筋急转弯。遍历值为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 

题目72658. 网格图中鱼的最大数目

解题思路: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 

题目81034. 边界着色

解题思路: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 
    

题目91020. 飞地的数量

解题思路: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  

题目102684. 矩阵中移动的最大次数

解题思路: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 

题目111254. 统计封闭岛屿的数目

解题思路: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 

题目12130. 被围绕的区域

解题思路: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

题目131905. 统计子岛屿

解题思路: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         
                    

题目141391. 检查网格中是否存在有效路径

解题思路: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)

题目15417. 太平洋大西洋水流问题

解题思路: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 

题目16529. 扫雷游戏

解题思路: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 

题目171559. 二维网格图中探测环

解题思路:点(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 

题目18827. 最大人工岛

解题思路:先计算(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 

题目19LCP 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(求最短路)

题目201926. 迷宫中离入口最近的出口

解题思路:最短路,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            
            

题目211091. 二进制矩阵中的最短路径

解题思路: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

题目221162. 地图分析

解题思路: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 

题目23542. 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 


题目24994. 腐烂的橘子

解题思路: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

题目251765. 地图中的最高点

解题思路: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 

题目26934. 最短的桥

解题思路:两遍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 

题目272146. 价格范围内最高排名的 K 样物品

解题思路: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] 

题目281293. 网格中的最短路径

解题思路:直接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

3 参考

灵神力扣题单