Skip to content

Add Solution to LC problem 980 #3980

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions dsa-solutions/lc-solutions/0900-0999/980 - Unique Paths III.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
---
id: unique-paths-iii
title: Unique Paths III
sidebar_label: Unique Paths III
tags: [Backtracking, DFS, Grid, C++, Python, Java]
description: Find the number of unique paths from the starting square to the ending square in a grid, walking over every non-obstacle square exactly once.
---

## Problem Statement

### Problem Description

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

**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:

(0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(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:

(0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
(0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,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)
(0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)


### 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.

## Solution

### Intuition

To solve this problem, we can use a backtracking approach with Depth-First Search (DFS). We will start from the starting square and try to explore all possible paths to the ending square while ensuring we visit every non-obstacle square exactly once. We will backtrack whenever we hit a dead end or revisit a square.

### Time Complexity and Space Complexity Analysis

- **Time Complexity**: $O(4^{m \times n})$, where $m \times n$ is the total number of cells. This is because, in the worst case, we might explore all possible paths.
- **Space Complexity**: $O(m \times n)$, for the recursion stack and the `visited` array.

### Code

#### C++

```cpp
class Solution {
public:
int uniquePathsIII(vector<vector<int>>& grid) {
int rows = grid.size();
int cols = grid[0].size();
int emptySquares = 1; // including the starting point
int startX, startY;

for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
if (grid[i][j] == 0) {
++emptySquares;
} else if (grid[i][j] == 1) {
startX = i;
startY = j;
}
}
}

return dfs(grid, startX, startY, emptySquares);
}

private:
int dfs(vector<vector<int>>& grid, int x, int y, int emptySquares) {
if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] == -1) {
return 0;
}
if (grid[x][y] == 2) {
return emptySquares == 0 ? 1 : 0;
}

grid[x][y] = -1;
int paths = dfs(grid, x + 1, y, emptySquares - 1) +
dfs(grid, x - 1, y, emptySquares - 1) +
dfs(grid, x, y + 1, emptySquares - 1) +
dfs(grid, x, y - 1, emptySquares - 1);
grid[x][y] = 0;

return paths;
}
};
```

#### Python
```python
class Solution:
def uniquePathsIII(self, grid: List[List[int]]) -> int:
rows, cols = len(grid), len(grid[0])
empty_squares = 1 # including the starting point
start_x, start_y = 0, 0

for i in range(rows):
for j in range(cols):
if grid[i][j] == 0:
empty_squares += 1
elif grid[i][j] == 1:
start_x, start_y = i, j

def dfs(x, y, empty_squares):
if x < 0 or x >= rows or y < 0 or y >= cols or grid[x][y] == -1:
return 0
if grid[x][y] == 2:
return 1 if empty_squares == 0 else 0

grid[x][y] = -1
paths = (dfs(x + 1, y, empty_squares - 1) +
dfs(x - 1, y, empty_squares - 1) +
dfs(x, y + 1, empty_squares - 1) +
dfs(x, y - 1, empty_squares - 1))
grid[x][y] = 0

return paths

return dfs(start_x, start_y, empty_squares)
```
#### Java
```java
class Solution {
public int uniquePathsIII(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;
int emptySquares = 1; // including the starting point
int startX = 0, startY = 0;

for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (grid[i][j] == 0) {
emptySquares++;
} else if (grid[i][j] == 1) {
startX = i;
startY = j;
}
}
}

return dfs(grid, startX, startY, emptySquares);
}

private int dfs(int[][] grid, int x, int y, int emptySquares) {
if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == -1) {
return 0;
}
if (grid[x][y] == 2) {
return emptySquares == 0 ? 1 : 0;
}

grid[x][y] = -1;
int paths = dfs(grid, x + 1, y, emptySquares - 1) +
dfs(grid, x - 1, y, emptySquares - 1) +
dfs(grid, x, y + 1, emptySquares - 1) +
dfs(grid, x, y - 1, emptySquares - 1);
grid[x][y] = 0;

return paths;
}
}
```
Loading