Count User Journey Prefixes
WhatnotSoftware Engineer · Online AssessmentLast updated
Process timestamped user activity logs to reconstruct chronological action sequences and count the frequency of user journey prefixes up to length k.
Problem Statement
In an e-commerce marketplace, understanding how users navigate the platform helps identify common drop-off points and popular discovery paths. You are given a list of user activity logs, where each log entry contains a user_id, an integer timestamp, and an action representing a page visit or interaction.
Your task is to reconstruct each user's chronological journey and count how many users completed each path prefix of length 1 up to k.
Specifically:
- Group the logs by
user_idand sort each user's actions in ascending order oftimestamp. - For each user, extract every prefix of their action sequence with length between
1andmin(k, len(user_actions)). - Count the number of unique users who experienced each prefix.
Return the counts as a dictionary (or hash map) where the key is a tuple of action strings representing the prefix, and the value is the integer count of users.
Interface
def count_user_prefixes(logs: list[tuple[str, int, str]], k: int) -> dict[tuple[str, ...], int]:
"""
Args:
logs: List of (user_id, timestamp, action) tuples.
k: Maximum prefix length to consider (1 <= k).
Returns:
A mapping from prefix tuples to the number of distinct users who have that prefix.
"""
Input & Output Format
- Input:
logs: A list of tuples(user_id, timestamp, action)whereuser_idis a string,timestampis an integer, andactionis a string.k: An integer representing the maximum length of prefixes to count.
- Output: A dictionary mapping
tuple[str, ...]toint.
Examples
Example 1
logs = [
("u1", 100, "home"),
("u2", 90, "home"),
("u1", 110, "item"),
("u1", 105, "search"),
("u2", 95, "search"),
("u2", 120, "cart"),
("u3", 50, "stream")
]
k = 2
output = count_user_prefixes(logs, k)
# Output:
# {
# ("home",): 2,
# ("home", "search"): 2,
# ("stream",): 1
# }
Explanation:
u1journey:["home", "search", "item"]. Prefixes up to length 2:("home",)and("home", "search").u2journey:["home", "search", "cart"]. Prefixes up to length 2:("home",)and("home", "search").u3journey:["stream"]. Prefixes up to length 2:("stream",).
Example 2
logs = [
("u1", 10, "login"),
("u1", 20, "login")
]
k = 3
output = count_user_prefixes(logs, k)
# Output:
# {
# ("login",): 1,
# ("login", "login"): 1
# }
Constraints
1 <= len(logs) <= 10^51 <= k <= 101 <= len(user_id), len(action) <= 300 <= timestamp <= 10^9- All
(user_id, timestamp)pairs are unique withinlogs.
Hints
Hint 1
Group log entries by user_id first so you can process each user independently.
Hint 2
Sort each user's entries by timestamp ascending to construct their correct chronological sequence of actions.
Hint 3
Iterate through prefix lengths from 1 to min(k, len(actions)) for each user and increment the prefix counter in a hash map.
Follow-up questions
- How would your approach change if the logs were a continuous, out-of-order stream that could not fit entirely in memory?
- If k was large (e.g., k = 1000) and we needed to query prefix counts dynamically, what data structure (e.g., a Trie) would be more space- and query-efficient?
- How would you handle sessions where an inactivity gap of more than 30 minutes splits a user's events into distinct journeys?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.