Recursively Expanded Shell Command Counts
Reported by candidates from Hudson River Trading's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Hudson River Trading reported this one in October 2026, and the data structure is the whole question: an array that stores each entry's resolved command. Command history with !index references looks like recursion bait, but it's really a single forward pass. If you're taking this OA in the next day or two, know the trick before you open the editor. StealthCoder sits invisibly on your screen as a safety net if you blank mid-assessment, but this problem is simple enough that you shouldn't need it once you see the shape.
The problem
You are given a command history. Every entry is one of the base commands cp, ls, and mv, or a history reference of the form !index. Each index is one-based, refers to an earlier entry, and executes the command represented by that entry. A reference may point to another reference, so resolve references recursively. Return the total execution counts in the order [cp, ls, mv], counting both direct executions and executions reached through references. Function countShellCommands(history: String[]) → int[] Examples Example 1 history = ["ls","cp","!1","!3","mv"] return = [1,3,1] Entries 1, 3, and 4 execute ls. The direct cp and mv entries execute once each. Example 2 history = ["cp","!1","!2"] return = [3,0,0] Both references ultimately resolve to cp, so all three entries execute that command. Example 3 history = ["mv","ls","cp","!2","!1","!4"] return = [1,3,2] The final reference points to entry 4, which resolves to ls. The totals are one cp, three ls executions, and two mv executions. Constraints 1 <= history.length <= 10^5. Every entry is cp, ls, mv, or !index. Every referenced index is between 1 and the current entry's one-based position minus 1.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Every reference points to an earlier entry, so when you reach entry i, entry j < i is already resolved. Keep an array resolved[i] holding 0, 1, or 2 for cp, ls, mv. For a base command, set it directly. For !k, copy resolved[k-1]. Then bump a counter for that command. One pass, O(n) time, O(n) space. The pitfall is writing actual recursion. A chain of 10^5 references can blow the stack, and re-resolving each chain repeatedly can go quadratic. Memoizing through the array avoids both. Also watch the one-based indexing, since !1 means history[0]. Parse the number from the substring after the bang, not a single character, because indexes can reach six digits. If you freeze live, StealthCoder can hand you this loop, but the array-of-resolved-commands idea is all you need.
If this hits your live OA and you blank, StealthCoder solves it in seconds, invisible to the proctor.
You can drill Recursively Expanded Shell Command Counts cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built by an Amazon engineer who would have shipped this the night before his JPMorgan OA if he'd had it.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Hudson River Trading's OA.
Hudson River Trading reuses patterns across OAs. Built by an Amazon engineer who would have shipped this the night before his JPMorgan OA if he'd had it. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Recursively Expanded Shell Command Counts FAQ
How hard is this Hudson River Trading OA question really?+
Easy once you spot it. It's a single pass with a lookup array. The difficulty is mostly in overthinking the recursion wording. If you resolve each entry as you read it, there's no real recursion left to write.
What's the trick to solving it in linear time?+
Store the resolved base command for every entry as you go. A reference just copies the stored value of the earlier entry it points to. Since references only point backward, that value is always ready. Increment the matching counter each time.
Do I need actual recursion or a stack?+
No. Recursion is risky with chains up to 10^5 deep and can overflow the call stack. Because every reference targets an earlier index, a forward loop with a memo array does the same job safely and in O(n).
What edge cases should I test?+
Test a history of length 1, a long chain like cp followed by !1, !2, !3 and so on, and multi-digit indexes such as !10 or !100000. Also check the one-based offset, since !1 refers to history[0]. Verify the output order is [cp, ls, mv].
How do I prepare in 48 hours?+
Write this one from scratch twice, then do a couple of other array-memoization problems where each element depends on earlier ones. Focus on parsing strings cleanly and indexing correctly. You don't need heavy theory for this, just clean forward-pass habits.