How to find 3 numbers in increasing order and increasing indices in an array in linear time
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The problem is to find indices i, j, and k such that i < j < k and arr[i] < arr[j] < arr[k], while still running in linear time. The usual trick is to precompute whether each position has a smaller value on its left and a larger value on its right, then scan once for a valid middle element.
Why A Naive Solution Is Too Slow
The brute-force approach checks every triple of indices, which costs O(n^3). Even a partially improved approach that fixes the middle element and searches left and right repeatedly can still degrade badly.
To stay in O(n), we need to preserve enough information from earlier and later positions so each index can be tested in constant time.
Build Left-Smaller And Right-Greater Arrays
The standard linear-time approach uses two helper arrays:
- '
left_smaller[j]stores the index of a smaller value that appears beforej, or-1if none exists' - '
right_greater[j]stores the index of a larger value that appears afterj, or-1if none exists'
Once those arrays are built, any position j with both values present is the middle of a valid increasing triplet.
This runs in O(n) time and uses O(n) extra space.
How The Helper Arrays Work
The left-to-right pass keeps track of the index of the smallest value seen so far. If the current element is greater than that minimum, then the minimum index becomes a valid left partner for the current position.
The right-to-left pass mirrors the idea. It keeps the index of the largest value seen to the right. If the current value is smaller than that maximum, then the maximum index becomes a valid right partner.
The final scan simply asks: "Is there a valid smaller value before this position and a valid larger value after it?" If yes, the triplet exists and the current element is the middle value.
Example Walkthrough
Take this array:
At index 4, the value is 6. The left-to-right pass has already recorded that 5 at index 3 is a smaller earlier value. The right-to-left pass has recorded that 30 at index 6 is a larger later value.
So index 4 is a valid middle position, and the algorithm can return the triplet (5, 6, 30) with indices (3, 4, 6).
This is the key insight: you do not need to enumerate every candidate triplet. You only need to know whether each position can serve as the middle.
Existence Versus Reconstruction
If the problem only asks whether such a triplet exists, you can sometimes use even less information. But if you want to return the actual numbers or indices, storing left and right helper arrays makes reconstruction straightforward.
That is why this O(n) plus O(n) approach remains a popular interview and implementation answer: it is efficient and it returns a concrete triplet without extra searching.
Common Pitfalls
- Checking only values and forgetting that the indices must also be in increasing order.
- Using strictly less-than conditions inconsistently when duplicates are present.
- Recomputing smaller-left or larger-right information inside the final scan and losing the linear-time guarantee.
- Returning the first three increasing values you see without verifying their index ordering.
- Confusing an existence-only optimization with an algorithm that must return the actual triplet.
Summary
- A valid solution needs both increasing values and increasing indices.
- The linear-time approach precomputes whether each index has a smaller value on the left and a larger value on the right.
- Any index with both helpers present is a valid middle element of the triplet.
- This gives
O(n)time and a direct way to reconstruct the actual answer.

