Last Day Where You Can Still Cross

Latest day on which a path exists from top to bottom while cells flood — reverse Union-Find.

Hard
Time O(R * C * α) Space O(R * C)
LeetCode
9 min read
union-find grid reverse-time

Problem#

A row x col grid starts with all land cells. Each day, one cell from cells (1-indexed) floods. Return the last day on which there is a 4-connected path from any top-row land cell to any bottom-row land cell.

Examples#

  • row = 2, col = 2, cells = [[1,1],[2,1],[1,2],[2,2]]2.
  • row = 2, col = 2, cells = [[1,1],[1,2],[2,1],[2,2]]1.

Constraints#

  • 2 <= row, col <= 2 * 10^4. cells.length == row * col.

Hints#

Hint 1
Going forward (flooding) is awkward; reverse time and add land each day.
Hint 2
Use two virtual nodes — top and bottom. Answer is the last day before they merge.

Approach#

Process cells in reverse order (day D down to 1). Start with everything water. On reverse day d, “add” the cell — union it with its already-added 4-neighbors. Also union top-row cells to a virtual TOP node and bottom-row cells to BOTTOM. As soon as find(TOP) == find(BOTTOM), return d - 1 (the last day before this cell was re-added, i.e., the day before the corresponding forward flooding step).

Solution#

Last Day Where You Can Still Cross
class DSU {
public:
vector<int> parent, rnk;
DSU(int n) : parent(n), rnk(n, 0) { iota(parent.begin(), parent.end(), 0); }
int find(int x) { while (parent[x] != x) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; }
void unite(int a, int b) {
a = find(a); b = find(b); if (a == b) return;
if (rnk[a] < rnk[b]) swap(a, b);
parent[b] = a; if (rnk[a] == rnk[b]) ++rnk[a];
}
};
class Solution {
public:
int latestDayToCross(int row, int col, vector<vector<int>>& cells) {
int N = row * col;
int TOP = N, BOT = N + 1;
DSU dsu(N + 2);
vector<vector<int>> grid(row, vector<int>(col, 0)); // 0 = water, 1 = land
int total = cells.size();
for (int d = total - 1; d >= 0; --d) {
int r = cells[d][0] - 1, c = cells[d][1] - 1;
grid[r][c] = 1;
int u = r * col + c;
if (r == 0) dsu.unite(u, TOP);
if (r == row - 1) dsu.unite(u, BOT);
static const int dr[4] = {-1, 1, 0, 0}, dc[4] = {0, 0, -1, 1};
for (int k = 0; k < 4; ++k) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < row && nc >= 0 && nc < col && grid[nr][nc])
dsu.unite(u, nr * col + nc);
}
if (dsu.find(TOP) == dsu.find(BOT)) return d;
}
return 0;
}
};

Editorial#

Going forward, the grid only loses connectivity — DSU doesn’t support disunion. Reversing time turns it into an addition problem (the classic offline DSU trick). We add the latest-flooded cell first; the answer is the latest day on which top still wasn’t connected to bottom — equivalently the iteration d at which adding the cell first connects them, returned as d.

Complexity#

  • Time: O(R * C * α(R * C)).
  • Space: O(R * C).

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.