Climb Detection with Recoverable Dips
Reported by candidates from Strava's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Strava's September 2026 OA hands you a elevation array and asks for the first climb as [start, end]. It looks like a peak-finding problem. It's really a single-pass state machine with one tricky rule: a dip after a peak only counts as survivable if it stays within 20% of the gain and the climb later beats that peak. If your invite lands in the next day or two, this is the one to understand cold. StealthCoder sits invisibly as a safety net if the dip rule scrambles your head mid-assessment.
The problem
Given an elevation sample array, return the first climb as [start, end], or an empty array when no climb exists. A climb starts at the last sample of a valley plateau immediately before the first strict increase. Equal elevations are allowed during a climb. Its endpoint is the first index at which its final maximum elevation is reached. After a maximum has been reached, a descent may be treated as a temporary dip only when every point in the dip loses at most 20% of the net gain from the climb start to that maximum and the elevation later becomes strictly greater than that maximum. Compare this threshold exactly as 5 * loss <= gain. Otherwise the climb ends at the first index of the current maximum. Function findFirstClimb(elevation: int[]) → int[] Examples Example 1 elevation = [3,2,1,0,0,1,2,2,3,5,10,10,7,15] return = [4,10] The last zero before the rise is index 4. The first elevation 10 is at index 10, and the later loss of 3 exceeds 20% of the gain of 10, so the climb ends there. Example 2 elevation = [0,5,4,6] return = [0,3] The one-unit dip is exactly 20% of the gain to 5 and is followed by a new maximum of 6, so the climb continues. Example 3 elevation = [5,4,4,1] return = [] The samples never rise, so there is no climb. Constraints 2 <= elevation.length <= 100000 -1000000 <= elevation[i] <= 1000000 All threshold comparisons must use the exact integer rule 5 * loss <= gain.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Reduce it to three steps. First, scan for the first strict increase i to i+1, then walk start back to the last sample of the plateau before it (the index just before the rise, which is i). Second, track the current max and its first index, letting equal values ride along. Third, once a drop begins after the max, track the lowest point in the dip and check 5 * loss <= gain, where gain is max minus start value. Then look ahead: if elevation goes strictly above max before the dip violates the rule, the climb continues and the max updates. If the rule breaks or the array ends first, return [start, firstIndexOfMax]. Pitfalls: updating the max index on ties (you need the first), using floating point for 20%, and checking only the final dip point instead of every point. Every point matters, so use the minimum. Keep it O(n). If you blank on the lookahead, StealthCoder is the hedge on the live OA.
The honest play: practice the pattern, and have StealthCoder ready for the one you didn't see coming.
You can drill Climb Detection with Recoverable Dips cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play.
Get StealthCoderYou've seen the question.
Make sure you actually pass Strava's OA.
Strava reuses patterns across OAs. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Climb Detection with Recoverable Dips FAQ
What's the core trick in the Strava climb detection problem?+
Treat it as a one-pass state machine. Find the first strict rise, anchor the start at the last plateau sample before it, then track the max and its first index. The only hard part is deciding whether a dip is recoverable, which needs the gain and the deepest loss.
How do I handle the 20% dip rule without bugs?+
Never use floats. Compute gain as max minus start value and loss as max minus the dip's lowest point, then test 5 * loss <= gain with integers. Check the lowest point in the dip, since every point must satisfy the rule, not just the last.
Where does the endpoint land when values tie at the max?+
At the first index where the final max was reached. Equal values during the climb are allowed, but they shouldn't move your endpoint. Only a strictly greater value updates the max and its index. Example 1 returns index 10, not 11.
What edge cases should I test before submitting?+
Test a strictly non-increasing array, which returns an empty array. Test a dip that's exactly 20%, which is allowed. Test a dip that's recoverable in threshold but never followed by a higher value, so the climb ends at the old max. Also test a rise at the very end.
How do I prepare for this in 48 hours?+
Write the scan yourself on the three examples, then break it with ties and exact-20% dips. Practice explaining the state variables: start, max, max index, dip minimum. If you can narrate them, the code follows. Aim for clean O(n) with no nested rescans.