# Unbroken

> A single dip resets the clock. Find the longest the machine held over the line.

Canonical URL: <https://datadriven.io/problems/unbroken-dose-stretch>

Domain: Python · Difficulty: easy · Seniority: junior

## Problem

A linac logs a dose reading each cycle, and a fault is only worth investigating when the machine sits at or above its safe ceiling for several cycles back to back. Given the readings and that ceiling, return the length of the longest unbroken stretch that stayed at or above it.

## Worked solution and explanation

### Why this problem exists in real interviews

Strip the medical costume off and this is the longest run of a predicate over a sequence, the canonical single-pass run-length warmup. The predicate here is reading >= ceiling. Everyone can test that condition; what separates candidates is keeping two numbers straight in one pass: the current streak and the best streak seen so far. The trap is conflating them, or trying to collect every run into a list and then maxing it, which is more code, more memory, and more places to get the reset wrong.

---

### Break down the requirements

#### Step 1: Track two counters, not one

current is the length of the run you are sitting in right now; longest is the best run you have closed out or are still extending. They are different numbers and you need both live at the same time. Collapsing them into one variable is the most common way this goes wrong.

#### Step 2: Extend or reset on each reading

When a reading meets the ceiling, the current run grows by one. When it falls below, the run is broken, so current snaps back to 0. There is no off-by-one here as long as you reset to 0, not 1: a sub-ceiling reading contributes nothing.

#### Step 3: Capture the max while the run is still alive

Update longest the moment current grows, not when the run ends. If you only record the max when a run breaks, the final run that runs off the end of the list never gets counted, which is the classic boundary bug. Updating in place sidesteps it entirely.

---

### The solution

**Single pass, two counters**

```python
def longest_stretch(readings, ceiling):
    longest = 0
    current = 0
    for r in readings:
        if r >= ceiling:
            current += 1
            if current > longest:
                longest = current
        else:
            current = 0
    return longest
```

> **Complexity**
>
> O(n) time, one pass over the readings, and O(1) extra space: two integers regardless of how many cycles the linac logged. Even a multi-million-reading log is a single linear scan, so there is no scaling story to worry about.

> **Interviewers Watch For**
>
> Whether you update longest inside the loop rather than after it, and whether you return 0 cleanly for an empty list or a list where nothing reaches the ceiling. Stating the empty-input behavior out loud before coding is the seniority tell on a warmup like this.

> **Common Pitfall**
>
> Only recording the max when the run breaks (on the else branch). On [10, 10, 10] the run never breaks, so the final, longest stretch is never captured and you return 0. Updating longest the moment current grows avoids it. The other miss is resetting current to 1 instead of 0, which silently inflates every count.

---

## Common follow-up questions

- Instead of the length, return the start and end indices of the longest stretch. What extra state do you carry? _(Tests tracking a run's origin index and snapshotting it when a new best is found, not just a counter.)_
- What if a single dip below the ceiling is allowed without breaking the stretch, but two in a row does break it? _(Tests generalizing the reset rule into a tolerance counter, a step toward sliding-window thinking.)_
- The readings now arrive as a stream you can only see once. Does your approach still work? _(Tests recognizing the algorithm is already online: O(1) state, no rescan, ready for an unbounded feed.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/unbroken-dose-stretch)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.