列表

详情


980. 不同路径 III

在二维网格 grid 上,有 4 种类型的方格:

返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目

每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格

 

示例 1:

输入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
输出:2
解释:我们有以下两条路径:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)

示例 2:

输入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]
输出:4
解释:我们有以下四条路径: 
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)

示例 3:

输入:[[0,1],[2,0]]
输出:0
解释:
没有一条路能完全穿过每一个空的方格一次。
请注意,起始和结束方格可以位于网格中的任意位置。

 

提示:

相似题目

解数独

不同路径 II

单词搜索 II

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int uniquePathsIII(vector<vector<int>>& grid) { } };

cpp 解法, 执行用时: 4 ms, 内存消耗: 6.8 MB, 提交时间: 2023-06-06 10:06:52

class Solution {
public:
    void DFS(int x, int y, int zero_count, int& path_count, vector<vector<int>>& grid)
    {
        //> 判断是否越界
        if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size())
            return;
        //> 为障碍,则结束
        if (grid[x][y] == -1)
            return ;
        //> 不仅要走到结束方格,还要每一个无障碍方格走一边
        if (grid[x][y] == 2 && zero_count != 0 )
            return;
        
        if (grid[x][y] == 2 && zero_count == 0)
        {
            path_count++;
            return ;
        }

        int temp = grid[x][y];
        //> 标记走过
        grid[x][y] = -1;
        //> 开始回溯
        DFS(x-1, y, zero_count-1 , path_count,grid);
        DFS(x+1, y, zero_count-1 , path_count,grid);
        DFS(x, y-1, zero_count-1 , path_count,grid);
        DFS(x, y+1, zero_count-1 , path_count,grid);
        grid[x][y] = temp;
    }
    int uniquePathsIII(vector<vector<int>>& grid) {
        //> 找到入口
        int x , y;
        path_count = 0;
        zero_count = 0;
        for (int i = 0; i < grid.size(); ++i)
        {
            for (int j = 0; j < grid[0].size(); ++j)
            {
                if (grid[i][j] == 1)
                {
                    x = i;
                    y = j;
                    zero_count++;
                }
                if (grid[i][j] == 0)
                    zero_count++;
            }
        }
        //> 参数,起始坐标x,y,当前还需走过的空方格,路径条数,二维网格
        DFS(x, y, zero_count, path_count,grid);
        return path_count;
    }
private:
    
        int path_count;
        int zero_count;
};

python3 解法, 执行用时: 60 ms, 内存消耗: 16.1 MB, 提交时间: 2023-06-06 10:06:25

class Solution:
    def uniquePathsIII(self, grid: List[List[int]]) -> int:
        def dfs(i, j, c):#分别是横纵坐标和步数
            if grid[i][j] == 2:#如果是终点
                return int(c == k + 1)#返回步数是否等于无障碍方格+终点数量
            res = 0
            for x, y in [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]]:
                if 0 <= x < m and 0 <= y < n and grid[x][y] != -1 and visit[x][y] == 0:
                    visit[x][y] = 1#回溯的经典场景,dfs之前标记已遍历,dfs之后标记未遍历
                    res += dfs(x, y, c + 1)
                    visit[x][y] = 0#标记未遍历
            return res
        m, n = len(grid), len(grid[0])
        visit = [[0 for i in range(n)] for j in range(m)]#和网格大小相同,用于标记方格是否被通过
        k = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:#记录起点
                    s = (i, j)
                elif grid[i][j] == 0:#对无障碍方格计数
                    k += 1
        visit[s[0]][s[1]] = 1#起点开始,所以已经遍历
        return dfs(s[0], s[1], 0)

java 解法, 执行用时: 91 ms, 内存消耗: 223.3 MB, 提交时间: 2023-06-06 10:05:59

class Solution {
    int ans;
    int[][] grid;
    int R, C;
    int tr, tc, target;
    int[] dr = new int[]{0, -1, 0, 1};
    int[] dc = new int[]{1, 0, -1, 0};
    Integer[][][] memo;

    public int uniquePathsIII(int[][] grid) {
        this.grid = grid;
        R = grid.length;
        C = grid[0].length;
        target = 0;

        int sr = 0, sc = 0;
        for (int r = 0; r < R; ++r)
            for (int c = 0; c < C; ++c) {
                if (grid[r][c] % 2 == 0)
                    target |= code(r, c);

                if (grid[r][c] == 1) {
                    sr = r;
                    sc = c;
                } else if (grid[r][c] == 2) {
                    tr = r;
                    tc = c;
                }
            }

        memo = new Integer[R][C][1 << R*C];
        return dp(sr, sc, target);
    }

    public int code(int r, int c) {
        return 1 << (r * C + c);
    }

    public Integer dp(int r, int c, int todo) {
        if (memo[r][c][todo] != null)
            return memo[r][c][todo];

        if (r == tr && c == tc) {
            return todo == 0 ? 1 : 0;
        }

        int ans = 0;
        for (int k = 0; k < 4; ++k) {
            int nr = r + dr[k];
            int nc = c + dc[k];
            if (0 <= nr && nr < R && 0 <= nc && nc < C) {
                if ((todo & code(nr, nc)) != 0)
                    ans += dp(nr, nc, todo ^ code(nr, nc));
            }
        }
        memo[r][c][todo] = ans;
        return ans;
    }
}

python3 解法, 执行用时: 80 ms, 内存消耗: 17.4 MB, 提交时间: 2023-06-06 10:05:38

'''
动态规划
让我们定义 dp(r, c, todo) 为从 (r, c) 开始行走,还没有遍历的无障碍方格集合为 todo 的好路径的数量。
'''
from functools import lru_cache
class Solution:
    def uniquePathsIII(self, grid: List[List[int]]) -> int:
        R, C = len(grid), len(grid[0])

        def code(r, c):
            return 1 << (r * C + c)

        def neibours(r, c):
            for nr, nc in ((r-1, c), (r, c-1), (r+1, c), (r, c+1)):
                if 0 <= nr < R and 0 <= nc < C and grid[nr][nc] % 2 == 0:
                    yield nr, nc

        target = 0
        for r, row in enumerate(grid):
            for c, val in enumerate(row):
                if val % 2 == 0:
                    target |= code(r, c)

                if val == 1:
                    sr, sc = r, c
                if val == 2:
                    tr, tc = r, c

        @lru_cache(None)
        def dp(r, c, todo):
            if r == tr and c == tc:
                return +(todo == 0)

            ans = 0
            for nr, nc in neibours(r, c):
                if todo & code(nr, nc):
                    ans += dp(nr, nc, todo ^ code(nr, nc))
            return ans

        return dp(sr, sc, target)

python3 解法, 执行用时: 68 ms, 内存消耗: 16.1 MB, 提交时间: 2023-06-06 10:04:31

class Solution:
    def uniquePathsIII(self, grid: List[List[int]]) -> int:
        R, C = len(grid), len(grid[0])

        def neibours(r, c):
            for nr, nc in ((r-1, c), (r, c-1), (r+1, c), (r, c+1)):
                if 0 <= nr < R and 0 <= nc < C and grid[nr][nc] % 2 == 0:
                    yield nr, nc

        todo = 0
        for r, row in enumerate(grid):
            for c, val in enumerate(row):
                if val != -1: todo += 1
                if val == 1: sr, sc = r, c
                if val == 2: tr, tc = r, c

        self.ans = 0
        def dfs(r, c, todo):
            todo -= 1
            if todo < 0: return
            if r == tr and c == tc:
                if todo == 0:
                    self.ans += 1
                return

            grid[r][c] = -1
            for nr, nc in neibours(r, c):
                dfs(nr, nc, todo)
            grid[r][c] = 0

        dfs(sr, sc, todo)
        return self.ans

java 解法, 执行用时: 0 ms, 内存消耗: 38.7 MB, 提交时间: 2023-06-06 10:03:10

// 回溯 + dfs
class Solution {
    int ans;
    int[][] grid;
    int tr, tc;
    int[] dr = new int[]{0, -1, 0, 1};
    int[] dc = new int[]{1, 0, -1, 0};
    int R, C;

    public int uniquePathsIII(int[][] grid) {
        this.grid = grid;
        R = grid.length;
        C = grid[0].length;

        int todo = 0;
        int sr = 0, sc = 0;
        for (int r = 0; r < R; ++r)
            for (int c = 0; c < C; ++c) {
                if (grid[r][c] != -1) {
                    todo++;
                }

                if (grid[r][c] == 1) {
                    sr = r;
                    sc = c;
                } else if (grid[r][c] == 2) {
                    tr = r;
                    tc = c;
                }
            }

        ans = 0;
        dfs(sr, sc, todo);
        return ans;
    }

    public void dfs(int r, int c, int todo) {
        todo--;
        if (todo < 0) return;
        if (r == tr && c == tc) {
            if (todo == 0) ans++;
            return;
        }

        grid[r][c] = 3;
        for (int k = 0; k < 4; ++k) {
            int nr = r + dr[k];
            int nc = c + dc[k];
            if (0 <= nr && nr < R && 0 <= nc && nc < C) {
                if (grid[nr][nc] % 2 == 0)
                    dfs(nr, nc, todo);
            }
        }
        grid[r][c] = 0;
    }
}

上一题