Reported October 2026
Robloxstack

Most Frequent Call Stack Per Thread

Reported by candidates from Roblox's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Roblox OA. Under 2s to a working solution.
Founder's read

Roblox sent this one in October 2026, and the whole solution hinges on one stack per thread. The problem looks like log parsing, but it's really a bookkeeping exercise. You track a call stack for every thread ID, count each full path when a function is entered, then pick a winner per thread. If you've got the OA coming up, this is a pattern you can walk through in your head tonight. And if you blank mid-assessment, StealthCoder runs invisibly on screen and gives you a working solution as a safety net.

The problem

You are given an array logs containing interleaved function-trace events from multiple threads. Each record has the format threadId|-> functionName for an entry or threadId|<- functionName for a return. Scan the records from left to right while maintaining one active call stack per thread.
Whenever a function is entered, count that thread's full active call path from the root to the entered function. Join function names with >, preserving the existing result representation. Return events update the matching thread's stack but do not add an occurrence.
Select one path independently for every thread:
Prefer the path with greater frequency.
If frequencies tie, prefer the deeper path.
The input guarantees that these two rules identify exactly one winning path for every observed thread.
Return one string per observed thread using the format threadId|winningPath|frequency. Order the result by threadId in ascending lexicographic order. If logs is empty, return an empty array.

Function
mostFrequentCallStackPerThread(logs: String[]) → String[]

Examples
Example 1
logs = ["worker-2|-> main","worker-1|-> main","worker-2|-> parse","worker-1|-> cache","worker-2|<- parse","worker-1|<- cache","worker-2|-> parse","worker-1|-> db","worker-2|<- parse","worker-1|<- db","worker-1|-> cache","worker-1|<- cache","worker-1|<- main","worker-2|<- main","worker-3|-> run","worker-3|<- run"]
return = ["worker-1|main>cache|2","worker-2|main>parse|2","worker-3|run|1"]
Entry events produce full paths; return events only pop their thread's stack. worker-1 enters main>cache twice, worker-2 enters main>parse twice, and worker-3 enters run once. Results are ordered by thread ID.
Example 2
logs = ["t|-> A","t|-> B","t|<- B","t|<- A"]
return = ["t|A>B|1"]
The paths A and A>B each occur once. The deeper path A>B wins the frequency tie.
Example 3
logs = ["t|-> main","t|-> beta","t|<- beta","t|-> alpha","t|<- alpha","t|-> beta","t|<- beta","t|<- main"]
return = ["t|main>beta|2"]
main>beta occurs twice, while main>alpha occurs once. The higher-frequency path wins.
Example 4
logs = []
return = []
No thread has an entry event, so there is no call path to return.

Constraints
0 <= logs.length <= 100000.
Each record contains exactly one | separator followed by -> or <-; an optional space may follow the arrow.
Each threadId is non-empty and contains only letters, digits, underscores, or hyphens.
Each function name is non-empty and contains only letters, digits, or underscores.
Every thread's trace is well formed and balanced, and each return matches the active stack's top.
After comparing frequency and then depth, each observed thread has exactly one winning path.
The maximum active depth of any thread is 50.
The total number of characters across all records is at most 2 * 10^6.

Reported by candidates. Source: FastPrep

Pattern and pitfall

Keep a hash map from threadId to a stack of function names, and a second map from threadId to a map of path string to count. On an entry event, push the name, join the stack with > to build the full path, and increment that path's count for the thread. On a return event, just pop. Don't count it. At the end, for each thread pick the path with the highest count, and break ties by depth, which is the number of > separators plus one. Then sort thread IDs lexicographically and format threadId|path|count. The common pitfalls are parsing the optional space after the arrow, counting returns by mistake, and rebuilding the path string from scratch in a slow way. Depth is capped at 50, so joining is cheap. If the parsing trips you up live, StealthCoder is the hedge that gets you unstuck.

Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.

If this hits your live OA

You can drill Most Frequent Call Stack Per Thread 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. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.

Get StealthCoder

Related leaked OAs

⏵ The honest play

You've seen the question. Make sure you actually pass Roblox's OA.

Roblox reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Most Frequent Call Stack Per Thread FAQ

What's the trick in the Roblox most frequent call stack problem?+

Keep one stack per thread in a hash map. On entry, push and record the joined path. On return, pop only. Then choose per thread by highest count, then deepest path. It's bookkeeping, not a hard algorithm.

How do I parse the log records safely?+

Split on the first | to get threadId and the rest. Check whether the rest starts with -> or <-. Strip the arrow, then trim any leading space to get the function name. Function names only contain letters, digits, and underscores, so trimming is safe.

How do I handle the tie-breaking rule?+

Compare by count first. If counts match, compare depth, which is the number of function names in the path. The input guarantees exactly one winner, so you don't need a third tiebreaker. Store the depth with the path or compute it from the stack length at entry.

Is the performance a concern with 100000 logs?+

No. Each entry builds a path with at most 50 names, so the work is linear in the logs. Total characters are capped at 2 million. Sorting the thread IDs at the end is cheap. Avoid re-scanning the logs per thread.

How do I prepare for this in 48 hours?+

Write it once end to end: parse, maintain stacks, count paths in nested maps, select winners, sort output. Test it against the four examples, especially the empty input and the depth tie. That covers almost every edge case this problem has.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Roblox.

OA at Roblox?
Invisible during screen share
Get it