加载中...
980-不同路径 III(Unique Paths III)
发表于:2021-12-03 | 分类: 困难
字数统计: 1.9k | 阅读时长: 10分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/unique-paths-iii

英文原文

You are given an m x n integer array grid where grid[i][j] could be:

  • 1 representing the starting square. There is exactly one starting square.
  • 2 representing the ending square. There is exactly one ending square.
  • 0 representing empty squares we can walk over.
  • -1 representing obstacles that we cannot walk over.

Return the number of 4-directional walks from the starting square to the ending square, that walk over every non-obstacle square exactly once.

 

Example 1:

Input: grid = [[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
Output: 2
Explanation: We have the following two paths: 
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)

Example 2:

Input: grid = [[1,0,0,0],[0,0,0,0],[0,0,0,2]]
Output: 4
Explanation: We have the following four paths: 
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)

Example 3:

Input: grid = [[0,1],[2,0]]
Output: 0
Explanation: There is no path that walks over every empty square exactly once.
Note that the starting and ending square can be anywhere in the grid.

 

Constraints:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 20
  • 1 <= m * n <= 20
  • -1 <= grid[i][j] <= 2
  • There is exactly one starting cell and one ending cell.

中文题目

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

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

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

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

 

示例 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
解释:
没有一条路能完全穿过每一个空的方格一次。
请注意,起始和结束方格可以位于网格中的任意位置。

 

提示:

  • 1 <= grid.length * grid[0].length <= 20

通过代码

官方题解

方法一:回溯深度优先搜索

思路与算法

让我们尝试遍历每一个 0 方格,并在走过的方格里留下一个障碍。回溯的时候,我们要删除那些自己留下的障碍。

介于输入数据的限制,这个方法是可以通过的,因为一个不好的路径很快就会因没有无障碍的方格可以走而被卡住。

[2RULHstn-Java]
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; } }
[2RULHstn-Python]
class Solution: def uniquePathsIII(self, grid): R, C = len(grid), len(grid[0]) def nei***ors(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 nei***ors(r, c): dfs(nr, nc, todo) grid[r][c] = 0 dfs(sr, sc, todo) return self.ans

复杂度分析

  • 时间复杂度:$O(4^{R*C})$,其中 $R, C$ 是这个二维网格行与列的大小。(我们可以找到一个更加精确的界限,但是这个界限已经超越了本文的范围)

  • 空间复杂度:$O(R*C)$。


方法二:动态规划

思路与算法

让我们定义 dp(r, c, todo) 为从 (r, c) 开始行走,还没有遍历的无障碍方格集合为 todo 的好路径的数量。

我们可以使用一个与 方法一 类似的方法,并通过记忆化状态 (r, c, todo) 的答案来避免重复搜索。

[pRtnUqNa-Java]
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; } }
[pRtnUqNa-Python]
from functools import lru_cache class Solution: def uniquePathsIII(self, grid): R, C = len(grid), len(grid[0]) def code(r, c): return 1 << (r * C + c) def nei***ors(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 nei***ors(r, c): if todo & code(nr, nc): ans += dp(nr, nc, todo ^ code(nr, nc)) return ans return dp(sr, sc, target)

复杂度分析

  • 时间复杂度:$O(R * C * 2^{R*C})$,其中 $R, C$ 是给定二维网格行与列的大小。
  • 空间复杂度:$O(R * C * 2^{R*C})$。

统计信息

通过次数 提交次数 AC比率
14932 20279 73.6%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言

相似题目

题目 难度
解数独 困难
不同路径 II 中等
单词搜索 II 困难
上一篇:
979-在二叉树中分配硬币(Distribute Coins in Binary Tree)
下一篇:
981-基于时间的键值存储(Time Based Key-Value Store)
本文目录
本文目录