Count Paths That Visit Every Open Cell Exactly Once
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ grid.length, grid[0].length ≤ 5 - ◆
Exactly one cell holds 1 (start) and exactly one holds 2 (end); -1 marks an obstacle, 0 an open walkable cell - ◆
Movement is one step at a time, horizontally or vertically, never onto an obstacle and never revisiting a cell already on the current path - ◆
A path only counts if it visits every non-obstacle cell exactly once before reaching the end
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Re-Scan the Whole Grid to Confirm Full Coverage
BruteExplore outward from the start with ordinary backtracking. Whenever the end cell is reached, check whether the path actually covered every open cell by scanning the entire grid and confirming each non-obstacle cell's visited flag is set. This gets the right answer, but the end cell can be reached by many different partial paths across the search — some covering everything, most not — and every single arrival re-scans the whole grid from scratch to find out which case it is.
O(3^(cells) · cells)O(cells)1class Solution {
2 public int countFullCoveragePaths(int[][] grid) {
3 int n = grid.length, m = grid[0].length;
4 int sr = 0, sc = 0;
5 boolean[][] visited = new boolean[n][m];
6 for (int r = 0; r < n; r++) {
7 for (int c = 0; c < m; c++) {
8 if (grid[r][c] == 1) { sr = r; sc = c; }
9 }
10 }
11 int[] count = new int[1];
12 dfs(grid, sr, sc, visited, count);
13 return count[0];
14 }
15
16 private void dfs(int[][] grid, int r, int c, boolean[][] visited, int[] count) {
17 int n = grid.length, m = grid[0].length;
18 if (r < 0 || r >= n || c < 0 || c >= m || visited[r][c] || grid[r][c] == -1) return;
19 if (grid[r][c] == 2) {
20 if (allVisited(grid, visited)) count[0]++;
21 return;
22 }
23 visited[r][c] = true;
24 dfs(grid, r + 1, c, visited, count);
25 dfs(grid, r - 1, c, visited, count);
26 dfs(grid, r, c + 1, visited, count);
27 dfs(grid, r, c - 1, visited, count);
28 visited[r][c] = false;
29 }
30
31 private boolean allVisited(int[][] grid, boolean[][] visited) {
32 int n = grid.length, m = grid[0].length;
33 for (int r = 0; r < n; r++) {
34 for (int c = 0; c < m; c++) {
35 if (grid[r][c] != -1 && !visited[r][c] && grid[r][c] != 2) return false;
36 }
37 }
38 return true;
39 }
40}Optimal — Track a Remaining-Cells Counter
OptimalCount the total number of non-obstacle cells once, up front. Carry a remaining count down through the recursion, one lower at every step taken. When the end cell is reached, full coverage is simply remaining == 1 — the end cell itself is the last one left to account for. No grid scan is ever needed: every arrival at the end cell already carries the exact number that answers "was everything covered," computed incrementally as the path was built rather than re-derived by inspection afterward.
O(3^(cells))O(cells)1class Solution {
2 public int countFullCoveragePaths(int[][] grid) {
3 int n = grid.length, m = grid[0].length;
4 int sr = 0, sc = 0, total = 0;
5 for (int r = 0; r < n; r++) {
6 for (int c = 0; c < m; c++) {
7 if (grid[r][c] == 1) { sr = r; sc = c; }
8 if (grid[r][c] != -1) total++;
9 }
10 }
11 boolean[][] visited = new boolean[n][m];
12 int[] count = new int[1];
13 dfs(grid, sr, sc, total, visited, count);
14 return count[0];
15 }
16
17 private void dfs(int[][] grid, int r, int c, int remaining, boolean[][] visited, int[] count) {
18 int n = grid.length, m = grid[0].length;
19 if (r < 0 || r >= n || c < 0 || c >= m || visited[r][c] || grid[r][c] == -1) return;
20 if (grid[r][c] == 2) {
21 if (remaining == 1) count[0]++;
22 return;
23 }
24 visited[r][c] = true;
25 dfs(grid, r + 1, c, remaining - 1, visited, count);
26 dfs(grid, r - 1, c, remaining - 1, visited, count);
27 dfs(grid, r, c + 1, remaining - 1, visited, count);
28 dfs(grid, r, c - 1, remaining - 1, visited, count);
29 visited[r][c] = false;
30 }
31}