Most Frequent Call Stack Per Thread
Problem statement
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
threadIdis 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.