# Unbroken

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

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

Domain: Python · Difficulty: easy · Seniority: junior

## Problem

A linac logs a dose reading each cycle, and instability shows up as a drop from one cycle to the next. Given the readings in order, return the length of the longest unbroken stretch where the dose never fell below the previous reading.

## Worked solution and explanation

### What this problem actually is

Strip the linac costume off and this is the longest non-decreasing run: the longest stretch where each reading is at least the one before it. The predicate is relational, r >= prev, and that is the whole point. Because whether a reading extends the run depends on its neighbor and not on the value alone, you cannot bucket the readings, count them, or throw them in a set. You carry three things through one pass: the previous reading, the length of the run you are sitting in, and the best run so far. The trap is comparing against a fixed number or the first reading instead of the immediate predecessor, or resetting the run to 0 on a drop when the dropping reading is itself a run of 1.

---

### Break down the requirements

#### Step 1: Compare to the previous reading, not a threshold

The qualifying condition is r >= prev, comparing each reading to the one immediately before it. Compare against a fixed ceiling or the first reading and you are solving a different problem. This relational check is also why a set, a dict, or a plain count cannot help you: extending the run is a decision about neighbors, not about a single value.

#### Step 2: On a drop, restart at 1, not 0

When a reading falls below its predecessor the current run breaks, but that dropping reading is the first reading of a fresh run, so current restarts at 1, not 0. Reset to 0 and every count after a drop comes back one short, and a strictly decreasing list wrongly returns 0 instead of 1.

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

Update the best the moment the current run grows, not when a drop happens. The longest run often ends at the last reading with nothing after it, so if you only record the best on a drop you silently discard the final stretch. Updating in place handles that boundary for free.

---

### The solution

**Single pass, track the predecessor and two counters**

```python
def longest_hold(readings):
    longest = 0
    current = 0
    prev = None
    for r in readings:
        if prev is None or r >= prev:
            current += 1
        else:
            current = 1
        if current > longest:
            longest = current
        prev = r
    return longest
```

> **Complexity**
>
> O(n) time, one pass over the readings, and O(1) extra space: a previous value and two integers no matter 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 compare to the immediate predecessor rather than a fixed value, whether you reset to 1 rather than 0, and whether you return 0 for empty input but 1 for a single reading. Saying the empty-versus-single-reading behavior out loud before you code is the seniority tell on a warmup like this.

> **Common Pitfall**
>
> Resetting current to 0 on a drop. A strictly decreasing list like [5, 4, 3, 2, 1] then returns 0, but each reading is a run of length 1, so the answer is 1. The other classic miss is only updating the best on a drop, which discards the final run on a monotonic input like [1, 2, 3, 4, 5].

---

## 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 snapshotting a run's origin index when a new best is found, not just a counter.)_
- What if a single drop is forgiven, so the stretch only breaks on two drops in a row? _(Tests generalizing the reset rule into a tolerance counter, a step toward sliding-window thinking.)_
- The readings now arrive as a stream you can see only 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)
- [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). DataDriven is the data engineering interview community. Live code execution in SQL, Python, and Spark sandboxes. Every feature is open to every member.