1. Recursive DFS Backtracking
Intuition
At each cell (r, c), check if within bounds and not an obstacle. Recurse to (r+1, c) and (r, c+1).
Algorithm
- Step 1: Check if start cell (0,0) or end cell (m-1, n-1) is 1. If so, return 0.
- Step 2: Define helper dfs(r, c).
- Step 3: If out of bounds or obstacleGrid[r][c] == 1, return 0.
- Step 4: If (r, c) == (m-1, n-1), return 1.
- Step 5: Return dfs(r + 1, c) + dfs(r, c + 1).
Recursive DFS Backtracking Trace
2 of 2 questions left todayStart at cell (0,0)
Start at cell (0,0). Valid start (val 0). Can branch Right to (0,1) or Down to (1,0).
#include <iostream>#include <vector> class Solution { int m, n; int dfs(int r, int c, const std::vector<std::vector<int>>& grid) { if (r >= m || c >= n || grid[r][c] == 1) return 0; if (r == m - 1 && c == n - 1) return 1; return dfs(r + 1, c, grid) + dfs(r, c + 1, grid); }public: int uniquePathsWithObstacles(const std::vector<std::vector<int>>& obstacleGrid) { if (obstacleGrid.empty() || obstacleGrid[0].empty()) return 0; m = obstacleGrid.size(); n = obstacleGrid[0].size(); return dfs(0, 0, obstacleGrid); }}; int main() { Solution solver; std::vector<std::vector<int>> grid = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}}; std::cout << "Unique Paths: " << solver.uniquePathsWithObstacles(grid) << std::endl; // 2 return 0;}Time & Space Complexity
- Time complexity:
O(2^(M + N))— Time complexity for Recursive DFS Backtracking. - Space complexity:
O(M + N)— Space complexity for Recursive DFS Backtracking.
Why Brute Force Doesn't Scale:
Recursive DFS without memoization visits 2^(M+N) states due to repeated subproblem recomputation.
For a 20x20 grid, DFS takes over 1011 operations whereas 1D Rolling DP executes in just 400 operations.