leetcode:980. 不同路径 III

题目

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

  • 1 表示起始方格。且只有一个起始方格。
  • 2 表示结束方格,且只有一个结束方格。
  • 0 表示我们可以走过的空方格。
  • -1 表示我们无法跨越的障碍。

返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目。
每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格。

示例:

  1. 输入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
  2. 输出:2
  3. 解释:我们有以下两条路径:
  4. 1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
  5. 2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,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)
输入:[[0,1],[2,0]]
输出:0
解释:
没有一条路能完全穿过每一个空的方格一次。
请注意,起始和结束方格可以位于网格中的任意位置。

解答 & 代码

递归回溯

class Solution {
private:
    // DFS 递归回溯
    // row、col 是当前坐标,nullCnt 是 grid 中 1、0 的数量(即合法路径除去终点的长度)
    // visitedCnt 是当前路径的长度,pathCnt 是合法路径数
    void backtrace(vector<vector<int>>& grid, int row, int col, int nullCnt, int visitedCnt, int& pathCnt)
    {
        int rows = grid.size();
        int cols = grid[0].size();
        // 递归结束条件
        if(row < 0 || row >= rows || col < 0 || col >= cols)    // 若坐标越界,直接返回
            return;
        if(grid[row][col] == 2)                                    // 若到达终点
        {
            if(nullCnt == visitedCnt)                            // 如果是合法路径,则 pathCnt +1
                ++pathCnt;
            return;
        }
        if(grid[row][col] != 1 && grid[row][col] != 0)            // 若当前格子是障碍(-1),直接返回
            return;

        // 选择
        ++visitedCnt;                // 当前路径长度 +1(访问了当前格子)
        grid[row][col] = -1;        // 将当前格子置为 -1,代表已访问过
        // 递归回溯:上、下、左、右四个方向
        backtrace(grid, row - 1, col, nullCnt, visitedCnt, pathCnt);
        backtrace(grid, row + 1, col, nullCnt, visitedCnt, pathCnt);
        backtrace(grid, row, col - 1, nullCnt, visitedCnt, pathCnt);
        backtrace(grid, row, col + 1, nullCnt, visitedCnt, pathCnt);
        // 撤销选择
        grid[row][col] = 0;
        --visitedCnt;
    }
public:
    int uniquePathsIII(vector<vector<int>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0)
            return 0;
        int rows = grid.size();
        int cols = grid[0].size();
        int pathCnt = 0;
        int nullCnt = 0;
        int startRow = -1;
        int startCol = -1;
        // 统计 0、1 的格子数 nullCnt,以及寻找到起点坐标
        for(int i = 0; i < rows; ++i)
        {
            for(int j = 0; j < cols; ++j)
            {
                if(grid[i][j] == 1 || grid[i][j] == 0)
                    ++nullCnt;
                if(grid[i][j] == 1)
                {
                    startRow = i;
                    startCol = j;
                }
            }
        }
        if(startRow == -1 || startCol == -1)
            return 0;

        backtrace(grid, startRow, startCol, nullCnt, 0, pathCnt);
        return pathCnt;
    }
};

复杂度分析:设矩阵为 m 行 n 列

  • 时间复杂度[困难] 980. 不同路径 III - 图1:合法路径包含 O(mn) 个格子(mn 个格子去掉障碍也是 O(mn) 个),在每个格子有上、下、左、右 4 种选择
  • 空间复杂度 O(mn):递归栈深度

执行结果:

执行结果:通过

执行用时:0 ms, 在所有 C++ 提交中击败了 100.00% 的用户
内存消耗:6.8 MB, 在所有 C++ 提交中击败了 62.18% 的用户