class Solution:
def uniquePathsIII(self, grid):
rows, cols = len(grid), len(grid[0])
empty = 1 # Start square counts as empty
sx = sy = 0
for i in range(rows):
for j in range(cols):
if grid[i][j] == 0:
empty += 1
elif grid[i][j] == 1:
sx, sy = i, j
self.ans = 0
def dfs(x, y, remain):
if x < 0 or x >= rows or y < 0 or y >= cols or grid[x][y] == -1:
return
if grid[x][y] == 2:
if remain == 0:
self.ans += 1
return
temp = grid[x][y]
grid[x][y] = -1
for dx, dy in [(-1,0),(1,0),(0,-1),(0,1)]:
dfs(x+dx, y+dy, remain-1)
grid[x][y] = temp
dfs(sx, sy, empty)
return self.ans
class Solution {
public:
int ans = 0;
int uniquePathsIII(vector<vector<int>>& grid) {
int rows = grid.size(), cols = grid[0].size();
int empty = 1, sx = 0, sy = 0;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
if (grid[i][j] == 0) empty++;
else if (grid[i][j] == 1) { sx = i; sy = j; }
}
}
dfs(grid, sx, sy, empty);
return ans;
}
void dfs(vector<vector<int>>& grid, int x, int y, int remain) {
int rows = grid.size(), cols = grid[0].size();
if (x < 0 || x >= rows || y < 0 || y >= cols || grid[x][y] == -1)
return;
if (grid[x][y] == 2) {
if (remain == 0) ans++;
return;
}
int temp = grid[x][y];
grid[x][y] = -1;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
for (auto& d : dirs)
dfs(grid, x+d[0], y+d[1], remain-1);
grid[x][y] = temp;
}
};
class Solution {
private int ans = 0;
public int uniquePathsIII(int[][] grid) {
int rows = grid.length, cols = grid[0].length;
int empty = 1, sx = 0, sy = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (grid[i][j] == 0) empty++;
else if (grid[i][j] == 1) { sx = i; sy = j; }
}
}
dfs(grid, sx, sy, empty);
return ans;
}
private void dfs(int[][] grid, int x, int y, int remain) {
int rows = grid.length, cols = grid[0].length;
if (x < 0 || x >= rows || y < 0 || y >= cols || grid[x][y] == -1)
return;
if (grid[x][y] == 2) {
if (remain == 0) ans++;
return;
}
int temp = grid[x][y];
grid[x][y] = -1;
int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
for (int[] d : dirs)
dfs(grid, x+d[0], y+d[1], remain-1);
grid[x][y] = temp;
}
}
var uniquePathsIII = function(grid) {
let rows = grid.length, cols = grid[0].length;
let empty = 1, sx = 0, sy = 0;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (grid[i][j] === 0) empty++;
else if (grid[i][j] === 1) { sx = i; sy = j; }
}
}
let ans = 0;
function dfs(x, y, remain) {
if (x < 0 || x >= rows || y < 0 || y >= cols || grid[x][y] === -1)
return;
if (grid[x][y] === 2) {
if (remain === 0) ans++;
return;
}
let temp = grid[x][y];
grid[x][y] = -1;
let dirs = [[-1,0],[1,0],[0,-1],[0,1]];
for (let [dx, dy] of dirs)
dfs(x+dx, y+dy, remain-1);
grid[x][y] = temp;
}
dfs(sx, sy, empty);
return ans;
};
The Unique Paths III problem asks you to find the number of unique paths from a given starting square to an ending square in a 2D grid. The grid contains four types of cells:
1
: The starting square (exactly one in the grid)2
: The ending square (exactly one in the grid)0
: Empty squares you can walk over-1
: Obstacles you cannot walk over1
and end at the square with 2
.0
) exactly once. You cannot walk over obstacles or revisit any square.0
and 1
and 2
) exactly once.grid
.
At first glance, this problem seems similar to a classic pathfinding problem, such as finding a path from start to end. However, the key twist is that you must visit every empty square exactly once, without revisiting or skipping any. This is similar to finding a Hamiltonian path in a grid, which is generally a hard computational problem.
A brute-force approach would be to try every possible path from the start to the end, checking if all empty squares are covered. However, this quickly becomes infeasible as the grid size increases, due to the exponential number of possible paths.
To optimize, we can use Depth-First Search (DFS) with backtracking. The idea is to recursively explore all possible moves, marking squares as visited and backtracking when necessary. We keep track of the number of squares left to visit, and only count a path as valid if it ends at the finish square with all empty squares visited.
We can solve this problem step-by-step as follows:
1
(the start), and count the total number of empty cells (0
). We also need to include the starting square as a square to visit.2
) and have visited all empty squares (tracked by a counter), we count it as a valid path.
We use in-place marking (e.g., setting the cell to -1
) to track visited cells, and backtrack to restore them after the recursive call. This avoids the need for an extra visited matrix.
Let's consider the following grid:
[[1,0,0,0], [0,0,0,0], [0,0,2,-1]]
Brute-force approach:
The Unique Paths III problem is a classic example of using DFS with backtracking to explore all possible paths under tight constraints (must visit all empty squares exactly once). The key insights are: