Spreading Contagion on a Grid
Company: OpenAI
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
## Spreading Contagion on a Grid
You are given an `m x n` integer grid `cells`. Each entry has one of three values:
- `0` — an empty location (no unit present).
- `1` — a **healthy** unit.
- `2` — an **infected** unit.
Time advances in discrete **minutes**. Every minute, any healthy unit (`1`) that is **4-directionally adjacent** (up, down, left, right) to an infected unit (`2`) becomes infected. All infections that can happen in a given minute happen simultaneously.
This problem has three independent parts. Each part is self-contained and uses the same grid encoding; solve all three.
---
### Part 1 — Time to full infection
Return the **minimum number of minutes** that must elapse until **no healthy unit** remains. If it is impossible for every healthy unit to become infected (some healthy unit can never be reached by the contagion), return `-1`.
**Function signature**
```python
def minutes_to_infect(cells: list[list[int]]) -> int:
...
```
**Example**
```text
Input: cells = [[2,1,1],
[1,1,0],
[0,1,1]]
Output: 4
```
```text
Input: cells = [[2,1,1],
[0,1,1],
[1,0,1]]
Output: -1
Explanation: The healthy unit in the bottom-left corner is never reached,
because infection only spreads 4-directionally.
```
```text
Input: cells = [[0,2]]
Output: 0
Explanation: There are already no healthy units at minute 0.
```
---
### Part 2 — Identify the immune units
Some healthy units can **never** become infected no matter how much time passes (they are unreachable from every initial infection source). Call such a unit **immune**.
Return the **count of immune units** in the grid (healthy units that the contagion can never reach). Empty locations (`0`) and infected locations (`2`) are not units and must not be counted.
**Function signature**
```python
def count_immune(cells: list[list[int]]) -> int:
...
```
**Example**
```text
Input: cells = [[2,1,1],
[0,1,1],
[1,0,1]]
Output: 1
Explanation: The bottom-left healthy unit is isolated from the contagion
and is the only immune unit.
```
---
### Part 3 — Time-limited immunity (dynamic)
Now immunity is acquired **dynamically over time**. You are given an additional integer `x`. A unit develops **lasting immunity** if it survives — i.e. stays healthy — for at least `x` consecutive minutes from the start. Concretely:
- A healthy unit that has **not yet been infected** by the end of minute `x - 1` (equivalently, a unit that is still healthy strictly after `x` minutes of spreading have been applied) becomes **permanently immune** and can **never** be infected afterward, even if an infected neighbor later appears next to it.
- Infections in minutes `1` through `x` still proceed normally on units that are not yet immune.
Because immunity is granted **at the same instant** that the contagion is still racing across the grid, a unit being infected in minute `x` versus becoming immune at minute `x` is a tie that must be resolved deterministically: **infection that lands at minute `x` takes effect; immunity is granted only to units that are still healthy after minute `x`'s infections are applied.**
Return the **number of units that are still healthy once the system reaches a steady state** (no further infections are possible). This count includes both units that became permanently immune at minute `x` and units that were never reachable at all.
**Function signature**
```python
def survivors_with_immunity(cells: list[list[int]], x: int) -> int:
...
```
**Examples**
```text
Input: cells = [[2,1,1,1,1]], x = 2
Output: 2
Explanation:
Minute 0: [2,1,1,1,1]
Minute 1: [2,2,1,1,1]
Minute 2: [2,2,2,1,1] <- after minute x=2's infections are applied,
the two rightmost units are still healthy
and become permanently immune.
Steady state: those 2 immune units remain healthy forever. Answer = 2.
```
```text
Input: cells = [[2,1,1]], x = 5
Output: 0
Explanation: The whole row is infected within 2 minutes, which is before
minute x=5, so no unit survives long enough to gain immunity.
```
```text
Input: cells = [[2,1],
[0,1]], x = 1
Output: 1
Explanation:
Minute 1: the top-right unit is infected; the bottom-right unit is not
adjacent to any infected unit yet, so it is still healthy after minute 1
and becomes permanently immune. Answer = 1.
```
### Constraints
- `1 <= m, n` and `m * n <= 10^4`.
- Each `cells[i][j]` is `0`, `1`, or `2`.
- For Part 3, `0 <= x <= m * n`. When `x == 0`, every healthy unit is immune from the start and the answer is the total count of healthy units.
- Note for Part 3: the dynamic immunity rule means a simple multi-source BFS that floods to completion is **not** sufficient — immunity must be applied at the correct time boundary, after which newly-arriving infection can no longer overwrite an immune unit.
Quick Answer: This question tests graph traversal and multi-source BFS on a 2D grid, evaluating a candidate's ability to model simultaneous state propagation across discrete time steps. It assesses graph reachability, connected-component analysis, and simulation under dynamic constraints — skills commonly probed in software engineering interviews to gauge algorithmic depth and practical coding fluency.
Spreading Contagion on a Grid — Part 1: Time to Full Infection
You are given an `m x n` integer grid `cells`. Each entry is one of:
- `0` — an empty location (no unit present)
- `1` — a **healthy** unit
- `2` — an **infected** unit
Time advances in discrete **minutes**. Every minute, any healthy unit (`1`) that is **4-directionally adjacent** (up, down, left, right) to an infected unit (`2`) becomes infected. All infections in a given minute happen **simultaneously**.
Return the **minimum number of minutes** that must elapse until **no healthy unit** remains. If it is impossible for every healthy unit to become infected (some healthy unit can never be reached by the contagion), return `-1`.
This is essentially the classic "rotting oranges" multi-source BFS.
**Examples**
```text
cells = [[2,1,1],[1,1,0],[0,1,1]] -> 4
cells = [[2,1,1],[0,1,1],[1,0,1]] -> -1 (bottom-left unit is unreachable)
cells = [[0,2]] -> 0 (no healthy units at minute 0)
```
Constraints
- 1 <= m, n and m * n <= 10^4
- Each cells[i][j] is 0, 1, or 2
Examples
Input: ([[2,1,1],[1,1,0],[0,1,1]],)
Expected Output: 4
Explanation: Classic rotting-oranges spread; the farthest healthy unit is infected at minute 4.
Input: ([[2,1,1],[0,1,1],[1,0,1]],)
Expected Output: -1
Explanation: The bottom-left healthy unit is isolated by empty cells and never gets infected, so full infection is impossible.
Input: ([[0,2]],)
Expected Output: 0
Explanation: There are no healthy units at minute 0, so 0 minutes are needed.
Input: ([[2,1,1,1,1]],)
Expected Output: 4
Explanation: Infection spreads one cell per minute along the row; the last cell is infected at minute 4.
Input: ([[0,0,0]],)
Expected Output: 0
Explanation: No healthy units present, so the answer is 0.
Input: ([[1]],)
Expected Output: -1
Explanation: A lone healthy unit with no infection source can never be infected, so return -1.
Input: ([[2]],)
Expected Output: 0
Explanation: Already infected, no healthy units, answer 0.
Input: ([[2,2],[1,1]],)
Expected Output: 1
Explanation: Both healthy units are adjacent to infected cells and become infected at minute 1.
Hints
- Use a multi-source BFS that starts from every infected cell (value 2) at once.
- Process the BFS level by level; each level is one minute. Track how many healthy units remain.
- After the BFS finishes, if any healthy unit is still uninfected it was unreachable, so return -1. If there were no healthy units to begin with, the answer is 0.
Spreading Contagion on a Grid — Part 2: Count the Immune Units
Same grid encoding as Part 1: `0` is empty, `1` is a healthy unit, `2` is an infected unit; infection spreads **4-directionally**, one ring per minute.
Some healthy units can **never** become infected, no matter how much time passes — they are unreachable from every initial infection source. Call such a unit **immune**.
Return the **count of immune units** in the grid (healthy units the contagion can never reach). Empty locations (`0`) and infected locations (`2`) are **not** units and must not be counted.
**Example**
```text
cells = [[2,1,1],[0,1,1],[1,0,1]] -> 1
```
The bottom-left healthy unit is isolated from the contagion and is the only immune unit.
Constraints
- 1 <= m, n and m * n <= 10^4
- Each cells[i][j] is 0, 1, or 2
Examples
Input: ([[2,1,1],[0,1,1],[1,0,1]],)
Expected Output: 1
Explanation: Only the isolated bottom-left healthy unit is never reached by the contagion.
Input: ([[2,1,1],[1,1,0],[0,1,1]],)
Expected Output: 0
Explanation: Every healthy unit is reachable from the infection source, so none are immune.
Input: ([[1,0,1]],)
Expected Output: 2
Explanation: There is no infection source at all, so both healthy units are immune.
Input: ([[2]],)
Expected Output: 0
Explanation: No healthy units, so no immune units.
Input: ([[1]],)
Expected Output: 1
Explanation: A lone healthy unit with no infection source is immune.
Input: ([[0,0]],)
Expected Output: 0
Explanation: No units at all, so the immune count is 0.
Input: ([[2,1,0,1,1]],)
Expected Output: 2
Explanation: The contagion reaches the unit at index 1, but the empty cell at index 2 blocks the two units on the right, which stay immune.
Input: ([[2,0,1],[0,0,1],[1,1,1]],)
Expected Output: 5
Explanation: The infected corner is walled off by empty cells; all five healthy units are unreachable and immune.
Hints
- Run a multi-source BFS/flood-fill from every infected cell, marking every healthy cell it can reach.
- Time does not matter for immunity — you only care about reachability, not minute counts.
- After the flood, count healthy cells (value 1) that were never marked reachable. Those are the immune units.
Spreading Contagion on a Grid — Part 3: Time-Limited (Dynamic) Immunity
Same grid encoding and 4-directional, one-ring-per-minute spread as Parts 1 and 2. Now you are also given an integer `x`, and immunity is acquired **dynamically over time**.
A unit develops **lasting immunity** if it stays healthy for at least `x` consecutive minutes from the start. Precisely:
- A healthy unit that has **not yet been infected** after `x` minutes of spreading have been applied becomes **permanently immune** and can **never** be infected afterward, even if an infected neighbor later appears next to it.
- Infections in minutes `1` through `x` proceed normally on units that are not yet immune.
- Tie-break: infection that lands **at minute `x`** takes effect; immunity is granted only to units still healthy **after** minute `x`'s infections are applied.
Return the **number of units still healthy once the system reaches a steady state** (no further infections are possible). This includes both units that became permanently immune at minute `x` and units that were never reachable at all.
When `x == 0`, every healthy unit is immune from the start, so the answer is the total number of healthy units.
**Key insight:** any unit still healthy right after minute `x` becomes immune, so after that boundary no healthy non-immune cell exists for the contagion to spread into. The answer is therefore simply the number of healthy cells remaining after running the multi-source BFS for at most `x` minutes.
**Examples**
```text
cells = [[2,1,1,1,1]], x = 2 -> 2 (after minute 2: [2,2,2,1,1]; the 2 right cells become immune)
cells = [[2,1,1]], x = 5 -> 0 (whole row infected within 2 minutes, before x)
cells = [[2,1],[0,1]], x = 1 -> 1 (bottom-right unit is still healthy after minute 1, so it is immune)
```
Constraints
- 1 <= m, n and m * n <= 10^4
- Each cells[i][j] is 0, 1, or 2
- 0 <= x <= m * n
- When x == 0, every healthy unit is immune from the start
Examples
Input: ([[2,1,1,1,1]], 2)
Expected Output: 2
Explanation: After minute 2 the grid is [2,2,2,1,1]; the two rightmost units are still healthy and become permanently immune.
Input: ([[2,1,1]], 5)
Expected Output: 0
Explanation: The whole row is infected within 2 minutes, well before x=5, so no unit survives long enough to gain immunity.
Input: ([[2,1],[0,1]], 1)
Expected Output: 1
Explanation: After minute 1 the top-right unit is infected; the bottom-right unit has no infected neighbor yet, so it stays healthy and becomes immune.
Input: ([[2,1,1]], 0)
Expected Output: 2
Explanation: With x=0 every healthy unit is immune from the start; there are 2 healthy units.
Input: ([[1,1,1]], 0)
Expected Output: 3
Explanation: No infection source and x=0, so all 3 healthy units survive.
Input: ([[2,1,1],[0,1,1],[1,0,1]], 1)
Expected Output: 5
Explanation: After minute 1 only one healthy unit (adjacent to the source) is infected; the remaining 5 healthy units are still healthy and become immune.
Input: ([[2,1,1,1,1]], 10)
Expected Output: 0
Explanation: x is larger than the time needed to infect the whole row, so the contagion floods to completion before immunity is granted; no survivors.
Input: ([[1]], 0)
Expected Output: 1
Explanation: A lone healthy unit with x=0 is immune from the start.
Input: ([[2]], 3)
Expected Output: 0
Explanation: There are no healthy units at all, so no survivors.
Input: ([[2,1,1],[0,1,1],[1,0,1]], 100)
Expected Output: 1
Explanation: x is large enough that the BFS floods to completion; only the permanently-unreachable bottom-left unit survives.
Hints
- Run the same multi-source BFS as Part 1, but stop after at most x level expansions (x minutes) instead of running to completion.
- After minute x, every cell that is still healthy becomes immune — including cells that were never reachable — so no further infection can occur.
- The answer is just the count of cells still equal to 1 once you stop the BFS. The tie-break (infection at minute x wins) is handled automatically because you apply minute x's infections before counting survivors.