Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Spend exactly `money` on two distinct flavors. Flavor ids are **1-based** positions in the `cost` array. One pass with a complement map: for each price `cost[i]`, if `money − cost[i]` was already seen, return `[seenIndex + 1, i + 1]`. Check the complement before inserting so a flavor never pairs with itself, and add 1 to each index to convert to a flavor id.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you see Two Sum behind the narrative and produce the 1-indexed ids without off-by-one slips.
Where candidates slip
Returning 0-based indices or prices, inserting before checking (self-pairing), or scanning the whole list per element instead of using a map.
How to stand out
Call it Two Sum up front, flag the +1 conversion as the only real difference, and note the result is sorted because the earlier index is returned first.
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 previewScan cost[i]need already seen?YesNoExplore the full treeCollapse the tree
How to read it:Find the complement price, then report 1-based ids.
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 — Nested Pair Scan
1Hint 1Explore hintHide hint
Exactly one pair sums to money — what's the most direct way to find it?
2Hint 2Explore hintHide hint
Try every pair (i, j) with j > i and check cost[i] + cost[j] == money.
3Hint 3Explore hintHide hint
Return ids i+1 and j+1 on the first match.
A · Core idea
Try all distinct position pairs and return the first whose prices sum to money. The inner loop begins at i + 1, so each pair is examined once and no flavor is paired with itself.
Why +1 on the result. Flavor ids are 1-based positions, so indices i and j become ids i + 1 and j + 1. With i < j, the ids are already in increasing order.
Why it's only a starting point. For up to 50 trips of n = 10⁴ flavors the quadratic scan passes, but it tells the interviewer you didn't reach for the hash map. State it, then improve.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
money = 5, cost = [2, 1, 3, 5, 6]Array state
i=0,j=2
2 + 3 = 5 → ids 1 and 3
1 3C · Code with teaching comments
Reference implementation previewpublic int[] whatFlavors(int[] cost, int money) { for (int i = 0; i < cost.length; i++) { for (int j = i + 1; j < cost.length; j++) { if (cost[i] + cost[j] == money) { return new int[]{i + 1, j + 1};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
Starting j at i + 1 makes the first discovered match come out smaller-id-first, so no extra sorting is needed.
ComplexityO(n²) time, O(1) space — Up to n(n−1)/2 pairs, each tested in O(1).
E · Edge cases and pitfalls5money = 4, cost = [2, 2] — Single pair → ids 1 2.Explore edge casesHide edge cases
Edge cases handled
money = 4, cost = [2, 2]Single pair → ids 1 2.money = 11, cost = [5, 6, 1]5 + 6 = 11 → ids 1 2.
Pitfalls
- Returning 0-based indices instead of 1-based ids.
- Returning prices instead of ids.
- Starting j at 0 — pairs a flavor with itself.
Approach 2 of 2 · Optimal
Complement Hash Map — One Pass (Optimal)
1Hint 1Explore hintHide hint
The partner price for cost[i] is money − cost[i]. What gives O(1) 'seen this price?' checks?
2Hint 2Explore hintHide hint
Map price → 0-based index; check the complement before inserting the current price.
3Hint 3Explore hintHide hint
On a hit, return [storedIndex + 1, i + 1] — +1 makes ids and the earlier index is smaller.
A · Core idea
Walk the cost list once. For flavor i priced cost[i], the complement money − cost[i] is the unique partner price. A hash map of previously seen prices answers 'have I seen that price?' in O(1).
Look up before inserting. Querying the complement before recording the current price keeps the two matched flavors at different indices — no flavor can complete the purchase by pairing with itself. cost = [2, 2], money = 4 works precisely because the first 2 is stored before the second 2 queries it.
Sorted ids for free. A found complement was stored at an earlier index, so returning [seen[need] + 1, i + 1] lists the smaller id first.
The 1-indexing. Indices are 0-based during iteration but ids are 1-based, so add 1 on return. Dropping that +1 is the single most common bug here.
With one guaranteed pair, return on the first match.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
money = 5, cost = [2, 1, 3, 5, 6]Hash-map state
i=0, price 2
3Continue scanning
need 3 absent → insert 2 → 0
1 3C · Code with teaching comments
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Strip the ice-cream narrative and this is Two Sum verbatim; the only original step is mapping a 0-based index to a 1-based id. Training yourself to unwrap story problems into their core pattern is the transferable skill — pairs of songs, complementary items, and 'two numbers that sum to X' are all this same map.
ComplexityO(n) time, O(n) space — One pass with O(1) average map ops → O(n) time; up to n−1 stored prices → O(n) space.
E · Edge cases and pitfalls5money = 4, cost = [2, 2, 4, 3] — First 2 stored, second 2 finds complement 2 at index 0 → ids 1 2.Explore edge casesHide edge cases
Edge cases handled
money = 4, cost = [2, 2, 4, 3]First 2 stored, second 2 finds complement 2 at index 0 → ids 1 2.money = 8, cost = [3, 5, 5]3 stored, first 5 finds 3 at index 0 → ids 1 2.
Pitfalls
- Forgetting the +1 and returning 0-based indices.
- Inserting before the complement check — can self-pair a flavor.
- Storing index → price, making the lookup O(n).
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic int[] whatFlavors(int[] cost, int money) { Map<Integer, Integer> seen = new HashMap<>(); for (int i = 0; i < cost.length; i++) { int need = money - cost[i]; if (seen.containsKey(need)) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Off-by-one on the flavor id
Ids are 1-based but indices are 0-based; returning the raw indices is one short of the expected id.
Explore the code comparisonHide the code comparison
Off-by-one on the flavor id
Ids are 1-based but indices are 0-based; returning the raw indices is one short of the expected id.
Don't write this
return new int[]{seen.get(need), i};Write this instead
return new int[]{seen.get(need) + 1, i + 1};2Insert before check (self-pair)
Recording cost[i] before the lookup lets a flavor match itself when 2·cost[i] == money, returning a duplicated id.
Explore the code comparisonHide the code comparison
Insert before check (self-pair)
Recording cost[i] before the lookup lets a flavor match itself when 2·cost[i] == money, returning a duplicated id.
Don't write this
seen[c] = i
if money - c in seen:
return [seen[money - c] + 1, i + 1]Write this instead
if money - c in seen:
return [seen[money - c] + 1, i + 1]
seen[c] = i3Returning prices, not ids
The story foregrounds costs, but the required output is the flavor ids.
Explore the code comparisonHide the code comparison
Returning prices, not ids
The story foregrounds costs, but the required output is the flavor ids.
Don't write this
return [c, money - c]Write this instead
return [seen[money - c] + 1, i + 1]Revise
Carry the pattern into the interview
Pattern to remember
Complement lookup, return 1-indexed ids
Code pattern to memorize
seen = {} # price -> 0-based index
for i, c in enumerate(cost):
if (money - c) in seen:
return [seen[money - c] + 1, i + 1]
seen[c] = iRules to remember
- 1Flavor id = array position + 1. Return ids, not 0-based indices and not prices.
- 2Look up
money − cost[i]before insertingcost[i]so the two flavors stay distinct. - 3The earlier-seen flavor has the smaller id, so
[seen[need]+1, i+1]is already increasing. - 4Map keys are prices (the thing you look up), values are indices (what you report).
- 5Exactly one pair exists per trip — return on the first match.
Use this pattern when
- Find the one pair of distinct items whose values reach a target
- Original ids/positions are required, not the values
- Unsorted prices where a single O(n) pass beats sorting
- The 'seen the partner already?' framing applies
Choose another pattern when
- Prices already sorted and space is tight → two pointers, O(1) space
- All pairs wanted, not just one → accumulate instead of returning
- Values wanted, not ids → no index bookkeeping needed
- Multiple valid pairs with a specific tie-break → revisit the stored value
Interview takeaway
Ice Cream Parlor is Two Sum with 1-based ids. The complement map finds the pair in one pass; the only added step is the +1 index-to-id conversion, and check-before-insert keeps the flavors distinct.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternStory-wrapped Two Sum with 1-based ids. Complement hash map finds the unique pair in one pass; the +1 index-to-id conversion is the only twist beyond the standard pattern.
Practice queueDirect variations and pattern siblings
Direct follow-ups