1. Exhaustive DFS Backtracking
Intuition
Recursively try every valid unvisited neighbor. Since DFS does not explore level-by-level, it must traverse all non-cyclic paths to verify the minimum.
Algorithm
- Step 1: If grid[0][0] == 1 or grid[n-1][n-1] == 1, return -1.
- Step 2: Define recursive dfs(r, c, currentLength, visited).
- Step 3: Base case: if (r, c) == (n-1, n-1), update minLength = min(minLength, currentLength).
- Step 4: For each of the 8 directions, if neighbor is in bounds, == 0, and not visited, mark visited, recurse, and unmark on backtrack.
- Step 5: Return minLength if found, else -1.
Exhaustive DFS Backtracking Trace
2 of 2 questions left todayStart DFS at root cell (0,0)
Start DFS at root cell (0,0). Valid open cell (val 0). Mark visited, path length = 1.
#include <iostream>#include <vector>#include <algorithm> class Solution { int minLen = 1e9; int n; int directions[8][2] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} }; void dfs(int r, int c, int len, std::vector<std::vector<int>>& grid, std::vector<std::vector<bool>>& visited) { if (len >= minLen) return; // Prune longer paths if (r == n - 1 && c == n - 1) { minLen = std::min(minLen, len); return; } visited[r][c] = true; for (auto& dir : directions) { int nr = r + dir[0]; int nc = c + dir[1]; if (nr >= 0 && nr < n && nc >= 0 && nc < n && grid[nr][nc] == 0 && !visited[nr][nc]) { dfs(nr, nc, len + 1, grid, visited); } } visited[r][c] = false; // Backtrack } public: int shortestPathBinaryMatrix(std::vector<std::vector<int>>& grid) { n = grid.size(); if (grid[0][0] != 0 || grid[n - 1][n - 1] != 0) return -1; std::vector<std::vector<bool>> visited(n, std::vector<bool>(n, false)); minLen = 1e9; dfs(0, 0, 1, grid, visited); return minLen == 1e9 ? -1 : minLen; }}; int main() { Solution solver; std::vector<std::vector<int>> g1 = {{0, 1}, {1, 0}}; std::cout << solver.shortestPathBinaryMatrix(g1) << std::endl; // 2 std::vector<std::vector<int>> g2 = {{0, 0, 0}, {1, 1, 0}, {1, 1, 0}}; std::cout << solver.shortestPathBinaryMatrix(g2) << std::endl; // 4 return 0;}Time & Space Complexity
- Time complexity:
O(8^(N^2))— Time complexity for Exhaustive DFS Backtracking. - Space complexity:
O(N^2)— Space complexity for Exhaustive DFS Backtracking.
Why Brute Force Doesn't Scale:
For N = 105, quadratic O(N2) approaches require ~1010 operations, exceeding the standard 1-second CPU budget.
The optimal approach processes N elements in a single or logarithmic pass, completing in under 10ms with minimal memory footprint.