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
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 longestCommon 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.)