Define and Calculate Employee Referral Counts
RobinhoodSoftware Engineer · OnsiteLast updated
Implement an algorithm to compute direct and total downstream referral counts for every employee in a directed graph that may contain duplicates, converging paths, and cycles.
Problem Statement
At Robinhood, referral programs reward users and employees for bringing new members onto the platform. Given a list of referral pairs where each pair (referrer, referred) indicates that referrer referred referred, calculate both the direct and total downstream referral counts for every employee present in the data.
- Direct referral count: The number of unique individuals directly referred by this employee.
- Downstream referral count: The total number of unique individuals reachable via one or more referral steps originating from this employee, excluding the employee themselves.
Due to potential data anomalies or co-referrals:
- The input may contain duplicate referral pairs.
- A person can be referred by multiple people (converging paths).
- Referral loops/cycles may exist (e.g., Alice refers Bob, and Bob refers Alice).
- An employee must never be counted as their own referral, even if reachable via a cycle.
- Any employee appearing in either position (referrer or referred) must be included in the output.
Function Signature
from typing import List, Tuple, Dict
def calculate_referral_counts(referrals: List[Tuple[str, str]]) -> Dict[str, Dict[str, int]]:
pass
Input & Output Format
- Input:
referrals, a list of tuples(referrer, referred)where each element is a string representing an employee ID. - Output: A dictionary mapping each employee ID to a dictionary with keys
"direct"and"downstream".
Constraints
0 <= len(referrals) <= 5,000- Number of unique employees
N <= 1,000 - Employee IDs are non-empty strings of alphanumeric characters.
Examples
Example 1: Converging Paths
referrals = [
("A", "B"),
("A", "C"),
("B", "D"),
("C", "D"),
]
output = calculate_referral_counts(referrals)
# Result:
# {
# "A": {"direct": 2, "downstream": 3}, # downstream: B, C, D
# "B": {"direct": 1, "downstream": 1}, # downstream: D
# "C": {"direct": 1, "downstream": 1}, # downstream: D
# "D": {"direct": 0, "downstream": 0}
# }
Example 2: Cycles and Duplicates
referrals = [
("A", "B"),
("B", "C"),
("C", "A"),
("A", "B"), # duplicate
("C", "D")
]
output = calculate_referral_counts(referrals)
# Result:
# {
# "A": {"direct": 1, "downstream": 3}, # downstream: B, C, D (A excluded)
# "B": {"direct": 1, "downstream": 3}, # downstream: C, D, A (B excluded)
# "C": {"direct": 2, "downstream": 3}, # downstream: A, B, D (C excluded)
# "D": {"direct": 0, "downstream": 0}
# }
Edge Cases
- Empty input list should return an empty dictionary.
- Self-referrals like
("A", "A"): direct and downstream counts forAshould both be0. - Disconnected components in the graph.
Hints
Hint 1
Deduplicate the edges upfront and collect every distinct employee ID into your adjacency list.
Hint 2
Because the graph may contain cycles and converging paths, tree-based recursion can double-count nodes or recurse infinitely; use a standard traversal (BFS or DFS) with a visited set per starting employee.
Hint 3
When computing reachable descendants for a node, ensure that the starting node is removed from or never added to the descendant set, even if a cycle leads back to it.
Follow-up questions
- How would you optimize this solution if the graph is guaranteed to be a Directed Acyclic Graph (DAG)?
- If the graph scale grows to millions of employees and referrals, how would you compute or approximate these reachability metrics in a distributed environment?
- How would you modify the data model and logic if referral bonuses decayed by generation distance (e.g., 100% for direct, 50% for 2nd tier, 25% for 3rd tier)?
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.