Arrays, Strings & Hashing
- Use a hash map to turn a re-scan into one pass over a stream of events
- Spot aggregation, carry-forward state and string matching, the three shapes Palantir reuses here
- Build the three most-reported problems, holdings, non-zero balances and subsequence matching, with the code run live
Arrays, strings, and hashing are the bread and butter of Palantir's live coding round. The single most-repeated problem in the whole loop lives right here: a stock-portfolio question that asks you to carry a set of holdings forward across dates. The round is a medium to medium-hard problem in a shared editor where the code runs. A working answer with the edge cases handled beats a clever one that fails a case. What ties the family together is the same instinct every time. You hold onto what you have already seen, netted, or counted in a hash map, and one pass answers a question a re-scan would answer slowly.
The Palantir texture is that these problems arrive wrapped in a story about real data. Field records, transaction ledgers, share positions over time. Part of the grade is pulling the actual specification out of that narrative before you touch the keyboard, then narrating the plan as you build. Forward Deployed Engineers spend their days wrangling a customer's messy data into something a platform like Foundry can reason over, so the round is a proxy for that work. Read the story, name the data model, reach for the map, and say why as you go.
How Palantir frames it
Three shapes carry nearly every array-and-hashing problem in this round. The first is aggregation: you walk a pile of records once and net or tally them into a map keyed by whatever the question groups on, an account, a ticker, a category. The second is carry-forward state, where you sweep an event timeline in order and keep a running value that persists across gaps, which is exactly the portfolio-holdings pattern. The third is string matching, where two pointers or a map of character positions decides whether one string sits inside another. All three trade a little memory for a single linear pass. Spot which shape you are in early, because that read is half the round.
A hash map is the cost-cut. Almost every problem in this family has a brute-force version that re-scans the data for each answer, and the map trades a little memory to collapse that inner loop into a lookup. A map from key to its running net, its count, or its last position turns a quadratic re-scan into one linear pass. The interviewer watches for you reaching for it and naming the trade. The code that follows is the easy part.
The core moves
Hash-map aggregation over messy records
The workhorse move is to walk a list of records once and fold them into a map. Counting tallies how often each key appears. Netting adds and subtracts signed amounts so the final value is the balance for that key. Both read the same in code: for each record, look up the key, apply the change, move on. The financial-ledger problems Palantir favors are pure netting, where money leaves one account and lands on another and you want the keys that did not settle back to zero. Same loop, different verb.
# Netting: fold signed amounts into a running balance per keynet = {} # key -> running balancefor src, dst, amount in transfers: net[src] = net.get(src, 0) - amount # money leaves the source net[dst] = net.get(dst, 0) + amount # money lands at the destinationunsettled = [k for k, bal in net.items() if bal != 0] # keys that did not net to zeroThe reason this beats re-scanning is that every record touches its key exactly once, so the whole aggregation is linear in the number of records. The same fold answers "how many," "how much," and "which keys are left over" by changing only what you store in the map. When the question asks you to split the tally along a second dimension, you widen the key rather than rebuild the loop. That is the door the follow-up on the ledger problem walks through.
Carry-forward state over a timeline
Some problems hand you dated events and ask for a value on every day, not just the days something happened. Sweep time in order while holding a running state that persists across empty stretches. A position you bought on Monday is still held on Tuesday even though Tuesday has no trade, so the running total simply carries. Group the events by day first, then walk the calendar, applying each day's changes and recording the total as you pass. The state never resets between days, which is what makes the gaps fill themselves in.
# Carry-forward: sweep days in order, running total persists across empty daysby_day = {}for day, key, delta in events: by_day.setdefault(day, []).append((key, delta))total = 0 # running value that carries across gapsfor day in range(min_day, max_day + 1): for key, delta in by_day.get(day, []): total += delta # apply this day's changes record(day, total) # a day with no events reuses the carried totalThe subtle part is the empty day. Because the total lives outside the loop over a single day's events, a day with nothing in by_day records the same value it held yesterday, which is the carry-forward the problem wants. Walking every calendar day is fine when the range is small. When the range grows to years with only a handful of events, that full sweep becomes the bottleneck, and that is precisely the escalation the interviewer reaches for.
Two-pointer and index-map string matching
The string questions here ask whether one sequence sits inside another. Two pointers is the base tool: advance through the text, ticking off the query's characters in order, and you have matched the whole query the moment the query pointer reaches the end. That single walk is linear in the length of the text. Many queries change the calculus. Now you preprocess once, mapping each character to the sorted list of positions where it occurs, then binary-search the next legal position per query character.
# Two pointers: is the query a subsequence of the text?i = 0 # position in the queryfor ch in text: if i < len(q) and ch == q[i]: i += 1 # matched the next query charactermatched = (i == len(q)) # true only if every query char was found in orderAsked at Palantir
Three problems, in the order the round tends to reward them. Daily portfolio holdings drills the carry-forward sweep and the sparse-range follow-up it is built around. Non-zero-balance accounts drills the netting fold, with a classification twist that mirrors how Palantir handles marked data. Query subsequence matching drills the two-pointer walk and the many-queries escalation. Work each one in the editor before you open the walkthrough. State the complexity of your plan as you build, because the round grades the narration as much as the code. The code runs against the cases, so surface your edge cases before they surface you.
Daily Portfolio Holdings: Carry-Forward Over Dates
Problem
[day, ticker, shares], where shares is positive for a buy and negative for a sell. Positions persist: shares bought on one day are still held on later days until sold.Return the total number of shares held across all tickers at the end of every day from the earliest event day to the latest event day, inclusive. A day with no events carries the previous day's total forward.
Return a list of
[day, totalShares] pairs, one per day in that range, in day order.Input encoding. Each test case is a JSON array
[events], where events is the list of [day, ticker, shares] records. The output is the list of [day, totalShares] pairs.Input: events = [[1,"AAPL",10],[1,"MSFT",5],[3,"AAPL",-4]]
Output: [[1,15],[2,15],[3,11]]
Day 1 buys 10 AAPL and 5 MSFT for a total of 15. Day 2 has no events, so the total carries to 15. Day 3 sells 4 AAPL, leaving 6 AAPL and 5 MSFT, a total of 11.
Input: events = [[1,"A",10],[2,"A",-10]]
Output: [[1,10],[2,0]]
Day 1 holds 10 shares. Day 2 sells all 10, so the total is 0.
Group the events by day, then sweep from the first day to the last while keeping one running total. A day with no events records the same total as the day before, which is the carry-forward.
Daily Portfolio Holdings: Carry-Forward Over Dates
Click "Run" to execute your code
Test Cases
[[[1,"AAPL",10],[1,"MSFT",5],[3,"AAPL",-4]]]Expected: [[1,15],[2,15],[3,11]][[[5,"X",3]]]Expected: [[5,3]][[[1,"A",10],[2,"A",-10]]]Expected: [[1,10],[2,0]][[[2,"A",4],[2,"B",6],[4,"A",-1],[5,"B",-6]]]Expected: [[2,10],[3,10],[4,9],[5,3]][[[10,"AAPL",100],[10,"AAPL",-100],[11,"GOOG",50]]]Expected: [[10,0],[11,50]]Non-Zero-Balance Accounts: Netting Over a Ledger
Problem
[source, destination, amount], meaning amount leaves source and arrives at destination.Return the list of account IDs whose net balance is not zero after all entries are applied, sorted in ascending order. An account that receives exactly what it sends nets to zero and is excluded.
Input encoding. Each test case is a JSON array
[transfers], where transfers is the list of [source, destination, amount] entries. The output is the sorted list of account IDs with a non-zero net balance.Input: transfers = [["A","B",30],["B","A",30],["A","C",5]]
Output: ["A", "C"]
A nets -30 + 30 - 5 = -5, B nets +30 - 30 = 0, C nets +5. B settled to zero, so only A and C remain.
Input: transfers = [["A","B",50],["B","A",50]]
Output: []
A and B each send and receive 50, so both net to zero and nothing is returned.
Fold the transfers into a map from account to running balance, subtracting from the source and adding to the destination. Then keep the keys whose balance is not zero and sort them.
Non-Zero-Balance Accounts: Netting Over a Ledger
Click "Run" to execute your code
Test Cases
[[["A","B",30],["B","A",30],["A","C",5]]]Expected: ["A","C"][[["A","B",50],["B","A",50]]]Expected: [][[["A","B",30],["B","C",10]]]Expected: ["A","B","C"][[["X","Y",100]]]Expected: ["X","Y"][[["A","B",10],["C","B",10],["B","A",10],["B","C",10]]]Expected: [][account, marking] pairs that did not settle. Keying by the pair keeps every classification on its own ledger. The marked version is worked below.Query Subsequence Match: Two Pointers, Then Many Queries
Problem
text. A query q matches the record if every character of q appears in text in the same order, though not necessarily next to each other. In other words, q is a subsequence of text.Return
true if q is a subsequence of text, and false otherwise. The empty query matches any record.Input encoding. Each test case is a JSON array
[text, q] of two strings. The output is a boolean.Input: text = "foundry", q = "fry"
Output: true
The characters f, r, y appear in "foundry" in that order (positions 0, 5, 6), so the query matches.
Input: text = "gotham", q = "gothamx"
Output: false
The query needs a trailing x that "gotham" does not contain, so it cannot match.
Two pointers. Walk the text once, advancing a query pointer whenever the current text character matches the query character it points at. The query is a subsequence exactly when that pointer reaches the end.
Query Subsequence Match: Two Pointers, Then Many Queries
Click "Run" to execute your code
Test Cases
["foundry","fry"]Expected: true["gotham","gothamx"]Expected: false["abcde","ace"]Expected: true["abcde","aec"]Expected: false["palantir",""]Expected: true["","x"]Expected: falseKey Takeaways
- ✓A hash map is the default cost-cut on the Palantir algorithm round. Aggregation nets or counts records into a map in one pass, carry-forward state sweeps an event timeline while a running value persists across gaps, and string matching walks two pointers or an index map. Reach for the map and name the trade as you do.
- ✓Daily portfolio holdings is the problem to expect by name. Group events by day, sweep the calendar with a running total that never resets between days, and the carry-forward across an empty day falls out for free. When the range grows to years, compress to change-points only.
- ✓The round grades the narration and the edge cases as much as the answer, because the code runs live. State the carry-forward rule, the zero-balance exclusion, and the empty-query case before the hidden cases reach them, and pull the real spec out of the story before you write a line.
- ✓Build for the follow-up, because it arrives fast. A sparse date range wants change-points, a classification marking widens the map key, and a stream of queries against a fixed record wants a one-time index. How cleanly you take the escalation is what separates a pass from a strong pass.
Palantir interview guideKnow what Palantir asks before you walk in.
20 coding · 6 system design · 17 behavioral questions
Get their questions first.
InterviewLegend is independent and not affiliated with or endorsed by any company it covers.