Skip to content

Commit 409f7c4

Browse files
chore: add LeetCode daily solution
1 parent 3f57010 commit 409f7c4

5 files changed

Lines changed: 186 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Last Day Where You Can Still Cross (Hard)
2+
3+
**Problem ID:** 1970
4+
**Date:** 2025-12-31
5+
**Link:** https://leetcode.com/problems/last-day-where-you-can-still-cross/
6+
7+
## Approach
8+
9+
To solve the problem of determining the last day where it is possible to walk from the top to the bottom of a binary matrix as cells become flooded, we can utilize a binary search approach combined with a flood-fill algorithm (such as BFS or DFS). Here's a concise explanation of the approach:
10+
11+
### Main Idea
12+
The key idea is to use binary search to efficiently find the last day where a path exists from the top row to the bottom row of the matrix. For each day in the binary search, we simulate the flooding of cells and check if a path can still be traversed.
13+
14+
### Steps
15+
1. **Binary Search Setup**:
16+
- Initialize two pointers: `left` at 0 (the first day) and `right` at `len(cells) - 1` (the last day).
17+
- The goal is to find the maximum day where crossing is still possible.
18+
19+
2. **Flooding Simulation**:
20+
- For a mid-point day in the binary search, create a matrix representation of the flooded state based on the `cells` array up to that day.
21+
- Mark the cells that have been flooded (set them to 1).
22+
23+
3. **Pathfinding**:
24+
- Use a flood-fill algorithm (BFS or DFS) to check if there exists a path from any cell in the top row (first row) to any cell in the bottom row (last row) using only the land cells (0s).
25+
- Start the search from all land cells in the top row and explore downwards, marking visited cells to avoid cycles.
26+
27+
4. **Adjusting Binary Search**:
28+
- If a path exists for the current mid-day, it means we can potentially find a later day, so move the `left` pointer to `mid + 1`.
29+
- If no path exists, it means we need to check earlier days, so move the `right` pointer to `mid - 1`.
30+
31+
5. **Result**:
32+
- The last valid day where a path exists will be stored in `right` after the binary search concludes.
33+
34+
### Data Structures
35+
- **Matrix**: A 2D array to represent the flooded state of the grid.
36+
- **Queue/Stack**: For BFS or DFS to explore the matrix and find paths.
37+
38+
### Complexity
39+
- **Time Complexity**: O((row * col) * log(days)), where `days` is the number of days (length of `cells`). Each day requires a flood-fill operation which takes O(row * col) time.
40+
- **Space Complexity**: O(row * col) for the matrix and additional space for the queue/stack used in the flood-fill.
41+
42+
This approach efficiently narrows down the search space while ensuring that we accurately check the connectivity of land cells in the matrix as it changes over the days.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class Solution {
2+
public int latestDayToCross(int row, int col, int[][] cells) {
3+
int left = 0, right = cells.length - 1;
4+
while (left < right) {
5+
int mid = left + (right - left + 1) / 2;
6+
if (canCross(row, col, cells, mid)) {
7+
left = mid;
8+
} else {
9+
right = mid - 1;
10+
}
11+
}
12+
return left;
13+
}
14+
15+
private boolean canCross(int row, int col, int[][] cells, int day) {
16+
boolean[][] grid = new boolean[row][col];
17+
for (int i = 0; i < day; i++) {
18+
int r = cells[i][0] - 1;
19+
int c = cells[i][1] - 1;
20+
grid[r][c] = true;
21+
}
22+
23+
boolean[] visited = new boolean[col];
24+
for (int j = 0; j < col; j++) {
25+
if (!grid[0][j]) {
26+
visited[j] = true;
27+
}
28+
}
29+
30+
for (int i = 0; i < row; i++) {
31+
boolean[] newVisited = new boolean[col];
32+
for (int j = 0; j < col; j++) {
33+
if (visited[j] && !grid[i][j]) {
34+
newVisited[j] = true;
35+
if (i == row - 1) {
36+
return true;
37+
}
38+
if (j > 0 && !grid[i][j - 1]) {
39+
newVisited[j - 1] = true;
40+
}
41+
if (j < col - 1 && !grid[i][j + 1]) {
42+
newVisited[j + 1] = true;
43+
}
44+
if (i < row - 1 && !grid[i + 1][j]) {
45+
newVisited[j] = true;
46+
}
47+
}
48+
}
49+
visited = newVisited;
50+
}
51+
return false;
52+
}
53+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
var latestDayToCross = function(row, col, cells) {
2+
const isValid = (grid) => {
3+
const visited = Array.from({ length: row }, () => Array(col).fill(false));
4+
const queue = [];
5+
6+
for (let c = 0; c < col; c++) {
7+
if (grid[0][c] === 0) {
8+
queue.push([0, c]);
9+
visited[0][c] = true;
10+
}
11+
}
12+
13+
while (queue.length) {
14+
const [r, c] = queue.shift();
15+
if (r === row - 1) return true;
16+
for (const [dr, dc] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) {
17+
const nr = r + dr, nc = c + dc;
18+
if (nr >= 0 && nr < row && nc >= 0 && nc < col && !visited[nr][nc] && grid[nr][nc] === 0) {
19+
visited[nr][nc] = true;
20+
queue.push([nr, nc]);
21+
}
22+
}
23+
}
24+
return false;
25+
};
26+
27+
let left = 0, right = cells.length - 1, answer = 0;
28+
29+
while (left <= right) {
30+
const mid = Math.floor((left + right) / 2);
31+
const grid = Array.from({ length: row }, () => Array(col).fill(0));
32+
33+
for (let i = 0; i <= mid; i++) {
34+
const [r, c] = cells[i];
35+
grid[r - 1][c - 1] = 1;
36+
}
37+
38+
if (isValid(grid)) {
39+
answer = mid + 1;
40+
left = mid + 1;
41+
} else {
42+
right = mid - 1;
43+
}
44+
}
45+
46+
return answer;
47+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
class Solution:
2+
def canCross(self, row, col, cells, day):
3+
grid = [[0] * col for _ in range(row)]
4+
for i in range(day):
5+
r, c = cells[i]
6+
grid[r - 1][c - 1] = 1
7+
8+
visited = [[False] * col for _ in range(row)]
9+
queue = collections.deque()
10+
11+
for c in range(col):
12+
if grid[0][c] == 0:
13+
queue.append((0, c))
14+
visited[0][c] = True
15+
16+
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
17+
18+
while queue:
19+
r, c = queue.popleft()
20+
if r == row - 1:
21+
return True
22+
23+
for dr, dc in directions:
24+
nr, nc = r + dr, c + dc
25+
if 0 <= nr < row and 0 <= nc < col and not visited[nr][nc] and grid[nr][nc] == 0:
26+
visited[nr][nc] = True
27+
queue.append((nr, nc))
28+
29+
return False
30+
31+
def latestDayToCross(self, row: int, col: int, cells: List[List[int]]) -> int:
32+
left, right = 1, len(cells)
33+
answer = 0
34+
35+
while left <= right:
36+
mid = (left + right) // 2
37+
if self.canCross(row, col, cells, mid):
38+
answer = mid
39+
left = mid + 1
40+
else:
41+
right = mid - 1
42+
43+
return answer

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,4 @@ Through completing the Blind 75 and NeetCode 150, you will have mastered:
321321
- 2025-12-28 — [Count Negative Numbers in a Sorted Matrix](https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix/) (Easy) → `Easy/2025-12-28-1351-Count-Negative-Numbers-in-a-Sorted-Matrix`
322322
- 2025-12-29 — [Pyramid Transition Matrix](https://leetcode.com/problems/pyramid-transition-matrix/) (Medium) → `Medium/2025-12-29-756-Pyramid-Transition-Matrix`
323323
- 2025-12-30 — [Magic Squares In Grid](https://leetcode.com/problems/magic-squares-in-grid/) (Medium) → `Medium/2025-12-30-840-Magic-Squares-In-Grid`
324+
- 2025-12-31 — [Last Day Where You Can Still Cross](https://leetcode.com/problems/last-day-where-you-can-still-cross/) (Hard) → `Hard/2025-12-31-1970-Last-Day-Where-You-Can-Still-Cross`

0 commit comments

Comments
 (0)