Unbroken

An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
easy
Seniority
junior
Asked in
Varian Medical Systems

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.

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

Example 1

Input:

readings = [3,5,7,2,8,9,10,1]

Output:

4

Example 2

Input:

readings = []

Output:

0

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
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

Common follow-up questions