Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
You have `money` to spend on exactly two distinct flavors whose prices sum to it. Return the two **1-indexed** flavor ids in increasing order. Use a complement hash map: as you scan the cost array, check whether `money − cost[i]` was already seen; if so return `[seenIndex + 1, i + 1]`. Storing value → index and checking before inserting yields the earlier id first, so the pair is already sorted.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you recognize Two Sum under the story and handle the 1-indexed output correctly.
Where candidates slip
Returning 0-based indices or the prices, inserting before the complement check (matching a flavor with itself), or storing index → value and losing O(1) price lookup.
How to stand out
Name it as Two Sum immediately, then point out the only real difference — the +1 conversion — and note that the earlier-index-first return is already sorted.
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 in seen?YesNoExplore the full treeCollapse the tree
How to read it:The only difference from Two Sum is the +1 when reporting 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
There's exactly one pair summing to money — what's the simplest way to find it?
2Hint 2Explore hintHide hint
Try every pair (i, j) with j > i and test cost[i] + cost[j] == money.
3Hint 3Explore hintHide hint
Return the ids i+1 and j+1 (1-based) the moment the sum matches.
A · Core idea
Examine every pair of distinct positions and return the first whose prices sum to money. The inner loop starts at i + 1 so each unordered pair is checked once and no flavor pairs with itself.
Why the +1 on return. The flavor id is the 1-based position, so the array indices i and j map to ids i + 1 and j + 1. Since i < j, the ids are already in increasing order.
Why not ship it. With n = 10⁴ per trip and up to 50 trips, the quadratic scan is acceptable but signals you missed the hash map. Mention it, state the cost, then improve.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
money = 4, cost = [1, 4, 5, 3, 2]Array state
i=0,j=3
1 + 3 = 4 → ids 1 and 4
1 4C · 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
Because j starts at i + 1, the first match found has the smaller id first — so the brute force already produces sorted ids with no extra work.
ComplexityO(n²) time, O(1) space — n(n−1)/2 pairs in the worst case, each checked 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 = 6, cost = [1, 2, 3, 5]1 + 5 = 6 → ids 1 4.
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
For price cost[i], the partner price is fixed: money − cost[i]. What structure answers 'have I seen this price?' in O(1)?
2Hint 2Explore hintHide hint
Map price → its 0-based index. For each flavor, check the complement before inserting.
3Hint 3Explore hintHide hint
If found, return [storedIndex + 1, i + 1] — the +1 converts to 1-based ids and the earlier index is the smaller id.
A · Core idea
Scan the cost list once. For each flavor priced cost[i], the only price that completes the purchase is money − cost[i]. Look that complement up in a hash map of previously seen prices; if present, the two flavors are found.
Why look up before inserting. Checking the complement against the map before recording the current price guarantees the two matched flavors sit at different indices — a flavor can never satisfy the purchase by pairing with itself. This is the same duplicate-safety property as Two Sum: cost = [2, 2], money = 4 returns ids 1 and 2 only because the first 2 was inserted before the second 2 looks it up.
Why the ids come out sorted. The complement, if present, was stored at an earlier index than the current one. Returning [seen[need] + 1, i + 1] therefore lists the smaller id first — no sorting step needed.
The 1-indexing. The map stores 0-based array indices because that's how we iterate, but flavor ids are 1-based, so we add 1 on the way out. Forgetting that single +1 is the most common wrong answer on this problem.
With exactly one guaranteed pair, we return on the first hit.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
money = 4, cost = [1, 4, 5, 3, 2]Hash-map state
i=0, price 1
3Continue scanning
need 3 absent → insert 1 → 0
1 4C · Code with teaching comments
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Recognizing the story as Two Sum is the whole game — once you do, the only original thinking left is the index-to-id (+1) conversion. Story-wrapped Two Sum shows up constantly (pair of songs, pair of items, complementary numbers); strip the narrative and reach for the complement map.
ComplexityO(n) time, O(n) space — One pass × O(1) average map ops = O(n); the map holds up to n−1 prices → O(n) space.
E · Edge cases and pitfalls5money = 4, cost = [2, 2, 4, 3] — First 2 inserted, second 2's complement 2 found at index 0 → ids 1 2.Explore edge casesHide edge cases
Edge cases handled
money = 4, cost = [2, 2, 4, 3]First 2 inserted, second 2's complement 2 found at index 0 → ids 1 2.money = 100, cost = [5, 75, 25]75 + 25 = 100 → ids 2 3 (75 stored before 25 looks it up).
Pitfalls
- Forgetting the +1 and returning 0-based indices.
- Inserting before the complement check — can pair a flavor with itself.
- Storing index → price, which makes the complement 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
Flavor ids are 1-based but the array and the map use 0-based indices. Returning the raw indices is one less than the expected id.
Explore the code comparisonHide the code comparison
Off-by-one on the flavor id
Flavor ids are 1-based but the array and the map use 0-based indices. Returning the raw indices is one less than 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)
If cost[i] is recorded before its complement is looked up and 2·cost[i] == money, the flavor matches itself, returning the same id twice.
Explore the code comparisonHide the code comparison
Insert before check (self-pair)
If cost[i] is recorded before its complement is looked up and 2·cost[i] == money, the flavor matches itself, returning the same id twice.
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 instead of ids
The story emphasizes costs, tempting you to return cost values. The expected output is the flavor ids.
Explore the code comparisonHide the code comparison
Returning prices instead of ids
The story emphasizes costs, tempting you to return cost values. The expected 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 returning 1-indexed ids
Code pattern to memorize
seen = {} # cost value -> 0-based index
for i, c in enumerate(cost):
need = money - c
if need in seen:
return [seen[need] + 1, i + 1] # +1 for 1-indexing
seen[c] = iRules to remember
- 1Return 1-indexed flavor ids, not the prices and not 0-based indices — the +1 is the whole trick here.
- 2Check
money − cost[i]in the map before insertingcost[i], so a flavor is never matched with itself. - 3The earlier index is the smaller id; returning
[seen[need] + 1, i + 1]is already in increasing order. - 4Store cost value → index. The complement is a price, and you need O(1) membership on prices.
- 5Exactly one valid pair is guaranteed per trip, so return immediately on the first match.
Use this pattern when
- Find the unique pair of distinct items whose values hit a target
- You need original positions/ids, not the values
- Unsorted input where a one-pass O(n) beats sorting
- A 'have I already seen the partner price?' framing fits
Choose another pattern when
- Prices are pre-sorted and O(1) space matters → two pointers
- You need all valid pairs, not the one guaranteed pair → collect instead of returning
- You need values rather than ids → drop the +1 index bookkeeping
- Duplicates must map to a specific tie-break beyond 'earliest' → reconsider the stored value
Interview takeaway
Ice Cream Parlor is Two Sum wearing a hat: the only twist is converting 0-based map indices into 1-based flavor ids on return. Check-before-insert keeps the two flavors distinct and the ids sorted.
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. Complement hash map for finding the unique pair, with a 1-based id conversion on return. Recognize the disguise quickly and the +1 is the only new work.
Practice queueDirect variations and pattern siblings
Direct follow-ups