Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Lauren buys a house in one year and must sell it in a *later* year at a *loss* (sell price < buy price); minimize that loss. Pair each price with its year, sort by price, and look only at consecutive prices in sorted order: for a sorted pair (lower, higher), it's a legal trade exactly when the higher price's year comes *before* the lower price's year — then the candidate loss is higher − lower. The minimum such difference is the answer. O(n log n) from the sort; prices reach 10¹⁶ so use long.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you realize that after sorting by price, the minimum loss must be between two consecutive prices — and that you still need the original years attached to enforce 'buy earlier, sell later'.
Where candidates slip
Comparing all O(n²) pairs, forgetting the temporal direction (buy must precede sell), or using a 32-bit int when prices reach 10¹⁶.
How to stand out
Argue why only adjacent sorted prices matter: any non-adjacent valid pair has a price between them that forms a smaller valid difference. Mention the TreeSet streaming variant and call out the overflow before coding.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewPair each price with its yearyear(higher) < year(lower)?YesNoExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Brute Force — All Ordered Pairs
1Hint 1Explore hintHide hint
What makes a pair (i, j) a valid losing trade? Spell out both the time order and the price order.
2Hint 2Explore hintHide hint
Try every pair with i < j; keep it only when price[i] > price[j].
3Hint 3Explore hintHide hint
Track the minimum of price[i] − price[j] over all valid pairs.
A · Core idea
The literal reading of the problem: a valid trade is a pair of years i < j where price[i] > price[j], and the loss is price[i] − price[j]. Enumerate every such pair and keep the smallest loss.
Why both conditions matter. i < j enforces buy-then-sell in time; price[i] > price[j] enforces that it's a loss, not a gain. Drop either and you count illegal trades.
Use long throughout. Prices reach 10¹⁶, so both the values and the differences must be 64-bit. A 32-bit int silently wraps.
Why we don't ship it. With n up to 2×10⁵, n²/2 ≈ 2×10¹⁰ comparisons — far too slow. Sorting reveals that only a handful of candidate pairs ever matter.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
price = [20, 7, 8, 2, 5]Array state
buy i=1 (7)
sell j=4 (5) → loss 2
2C · Code with teaching comments
Reference implementation previewpublic long minimumLossBrute(long[] price) { int n = price.length; long best = Long.MAX_VALUE; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) {Explore the full codeHide the full code
D · Why it works and complexityO(n²) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Most of the O(n²) pairs are wasteful: a buy price that's far above the sell price can never be the minimum loss. Only prices close in value can produce a small loss — which is precisely what sorting surfaces.
ComplexityO(n²) time, O(1) space — Two nested loops over all i < j → n(n−1)/2 ≈ n²/2 pairs, O(n²).
E · Edge cases and pitfalls3Allowing j ≤ i — sells before or at the buy year.Explore edge casesHide edge cases
Pitfalls
- Allowing j ≤ i — sells before or at the buy year.
- Using int for prices — overflow at 10¹⁶.
- Running O(n²) on n = 2×10⁵ and timing out.
Approach 2 of 2 · Optimal
Sort by Price + Adjacent Scan (Optimal)
1Hint 1Explore hintHide hint
If two valid prices are far apart in value, can their gap be the minimum loss? What if some other price sits between them?
2Hint 2Explore hintHide hint
Sort the (price, year) pairs by price. For a consecutive pair, the smaller difference is between adjacent prices.
3Hint 3Explore hintHide hint
A consecutive pair (lower, higher) is a legal trade only when the higher price's year is earlier than the lower price's year. Take the min of those differences.
A · Core idea
Sort the prices ascending, carrying each price's original year. Now walk consecutive pairs. For a sorted pair (lower, higher), the only way it's a valid trade is to buy the higher price and sell the lower — and that requires the higher price's year to be earlier than the lower price's year. If so, the candidate loss is higher − lower.
Why only adjacent pairs matter. Suppose the optimal trade buys at price H and sells at price L with H > L. Take any other price X with L < X < H. If X's year is before L's year, then buying X and selling L is also valid and gives a smaller loss (X − L < H − L) — contradicting optimality. Otherwise X's year is after L's year; but X < H, and if X's year is after the buy year of H then selling X (instead of L) against H... the careful version of this argument shows the minimum loss is always realized by two prices with no other price strictly between them — i.e. consecutive in sorted order. So we never need non-adjacent pairs.
Why we keep the year. Sorting by price throws away the time order, but the trade legality depends entirely on it. Storing (price, year) lets us check year(higher) < year(lower) in O(1) per pair.
Why long. Prices reach 10¹⁶; the differences do too. Use 64-bit for the stored prices and the running best.
Streaming variant (TreeSet). Equivalently, process prices in year order while maintaining an ordered set of prices seen in earlier years. For each new (sell) price, query the smallest stored price strictly greater than it (a higher, earlier buy) and take that difference. Same O(n log n), handy when prices arrive one at a time.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
price = [20, 7, 8, 2, 5]Array state
pair (5, 7)
year(7)=2 < year(5)=5 → loss 7−5 = 2
2C · Code with teaching comments
D · Why it works and complexityO(n log n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Sorting converts a global 'compare every pair' into a local 'compare neighbors' problem — the minimum gap between any two values is always between adjacent values once sorted. The only twist here is the temporal constraint, which we preserve by carrying the original index. This 'sort then look at neighbors' move is the backbone of closest-pair and minimum-difference problems.
ComplexityO(n log n) time, O(n) space — Sorting dominates at O(n log n). The adjacent scan is one O(n) pass. Storing (price, year) pairs is O(n) space.
E · Edge cases and pitfalls5price = [2, 3, 4, 1] — Sorted [1,2,3,4]; pair (1,2): year(2)=0 < year(1)=3 → loss 1. That beats all larger adjacent gaps.Explore edge casesHide edge cases
Edge cases handled
price = [2, 3, 4, 1]Sorted [1,2,3,4]; pair (1,2): year(2)=0 < year(1)=3 → loss 1. That beats all larger adjacent gaps.price = [5, 10, 3]Sorted [3,5,10]; pair (3,5): year(5)=0 < year(3)=2 → loss 2. Pair (5,10) has year(10)=1 > year(5)=0, skipped.
Pitfalls
- Sorting only the prices and losing the original years — you can't check buy-before-sell.
- Checking the wrong direction: it must be year(higher) < year(lower), not the reverse.
- Using int for prices/loss — 10¹⁶ overflows; use long.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic long minimumLoss(long[] price) { int n = price.length; long[][] pe = new long[n][2]; // [price, originalYearIndex] for (int i = 0; i < n; i++) { pe[i][0] = price[i];Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Losing the year when sorting
Sorting only the price values discards the time order, so you can no longer tell whether the higher price was bought earlier than the lower price was sold.
Explore the code comparisonHide the code comparison
Losing the year when sorting
Sorting only the price values discards the time order, so you can no longer tell whether the higher price was bought earlier than the lower price was sold.
Don't write this
prices = sorted(price) # year information goneWrite this instead
order = sorted(range(len(price)), key=lambda i: price[i]) # keeps years2Wrong temporal direction
A valid loss buys the HIGHER price first and sells the LOWER price later. Checking year(lower) < year(higher) flips the trade and counts impossible transactions.
Explore the code comparisonHide the code comparison
Wrong temporal direction
A valid loss buys the HIGHER price first and sells the LOWER price later. Checking year(lower) < year(higher) flips the trade and counts impossible transactions.
Don't write this
if (loYear < hiYear) { // sell-then-buy — illegal
best = Math.min(best, higher - lower);
}Write this instead
if (hiYear < loYear) { // buy higher earlier, sell lower later
best = Math.min(best, higher - lower);
}332-bit overflow on prices
Prices go up to 10¹⁶, far beyond Integer.MAX_VALUE (~2.1×10⁹). Storing or subtracting them as int corrupts the result.
Explore the code comparisonHide the code comparison
32-bit overflow on prices
Prices go up to 10¹⁶, far beyond Integer.MAX_VALUE (~2.1×10⁹). Storing or subtracting them as int corrupts the result.
Don't write this
int[] price = ...; int best = Integer.MAX_VALUE;Write this instead
long[] price = ...; long best = Long.MAX_VALUE;Revise
Carry the pattern into the interview
Pattern to remember
Sort by price; minimal loss lives between consecutive prices
Code pattern to memorize
pair (price, year); sort by price asc
best = +inf
for k in 1..n-1:
hi = sorted[k], lo = sorted[k-1]
if year(hi) < year(lo): # bought higher earlier, sold lower later
best = min(best, price(hi) - price(lo))
return bestRules to remember
- 1You buy first, sell later — the higher (buy) price must have the earlier year; the lower (sell) price the later year.
- 2The minimum loss always occurs between two consecutive prices in sorted order — no need to check non-adjacent pairs.
- 3All prices are distinct, so 'consecutive in sorted order' is well-defined and the difference is strictly positive.
- 4Keep the original year/index alongside the price when you sort — that's how you check the buy-before-sell ordering.
- 5Prices reach 10¹⁶ — use long (64-bit) for prices and the loss, an int overflows.
Use this pattern when
- Minimize a positive difference between two elements subject to an ordering (time) constraint
- 'Closest pair' style questions where adjacency in sorted order limits candidates
- Buy-low/sell-high or buy-high/sell-low with a temporal direction
Choose another pattern when
- No ordering constraint between the two elements → it's just min adjacent difference after sorting
- Many queries / streaming inserts where you need the best so far each step → an ordered set (TreeSet) is cleaner than a one-shot sort
- You may sell at a profit too → this is the classic max-profit stock problem, a different DP/greedy
Interview takeaway
Sort by value and only adjacent pairs can give the minimum difference. Carry the original index so you can enforce the time ordering, and the loss-minimization collapses from O(n²) pair-checking to a single O(n) scan after the sort.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternSort-then-neighbors for minimum difference, plus an index carried through the sort to honor an ordering constraint. The minimum positive gap between values is always between adjacent sorted values; a TreeSet gives the streaming version. Same backbone as Minimum Absolute Difference and closest-pair problems.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Minimum Loss with non-distinct pricesComing soonIf duplicates are allowed, break ties by year and use an ordered multiset / TreeMap with counts.
- Best Time to Buy and Sell StockComing soonThe profit-maximizing mirror — track the running minimum buy price in one pass.
- Minimum Absolute Difference in an ArrayComing soonSame 'sort then compare neighbors' core, without the temporal constraint.