Implement a Referral Network
Company: Mercor
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates skills in modeling and manipulating directed acyclic graphs, implementing graph-based ranking metrics (reachability and flow centrality), and reasoning about stochastic growth and expected-value computations, testing competencies in graph algorithms, data structures, combinatorics, and probabilistic modeling within the Coding & Algorithms domain. It is commonly asked because it probes both practical implementation ability and algorithmic thinking—requiring deterministic traversal and ranking logic as well as conceptual understanding of probabilistic growth models and trade-offs between exact dynamic programming, approximations, and simulation—thereby assessing both practical application and conceptual understanding.
Part 1: Process Core Referral Graph Operations
Constraints
- 0 <= len(operations) <= 10^4
- User IDs are non-empty strings of length at most 50
- Each user may have at most one direct referrer
- The graph must remain acyclic after every successful referral
Examples
Input: ([('ADD_USER', 'A'), ('ADD_USER', 'B'), ('ADD_REFERRAL', 'A', 'B'), ('GET_DIRECT_REFERRALS', 'A'), ('GET_REFERRER', 'B')],)
Expected Output: [True, True, True, ['B'], 'A']
Explanation: Basic add/query flow.
Input: ([('ADD_USER', 'A'), ('ADD_USER', 'A'), ('ADD_REFERRAL', 'A', 'B'), ('ADD_REFERRAL', 'A', 'B'), ('GET_DIRECT_REFERRALS', 'A'), ('GET_REFERRER', 'B')],)
Expected Output: [True, False, True, False, ['B'], 'A']
Explanation: Adding an existing user returns False, and a duplicate referral is rejected.
Input: ([('ADD_REFERRAL', 'A', 'B'), ('ADD_REFERRAL', 'C', 'B'), ('GET_REFERRER', 'B'), ('GET_DIRECT_REFERRALS', 'C')],)
Expected Output: [True, False, 'A', []]
Explanation: B already has direct referrer A, so C -> B is rejected. C still exists because users are auto-created.
Input: ([('ADD_REFERRAL', 'A', 'B'), ('ADD_REFERRAL', 'B', 'C'), ('ADD_REFERRAL', 'C', 'A'), ('GET_DIRECT_REFERRALS', 'C'), ('GET_REFERRER', 'A')],)
Expected Output: [True, True, False, [], None]
Explanation: C -> A would create a cycle A -> B -> C -> A, so it is rejected.
Input: ([('GET_DIRECT_REFERRALS', 'X'), ('GET_REFERRER', 'X')],)
Expected Output: [[], None]
Explanation: Edge case: queries for an unknown user.
Hints
- Keep two hash maps: one from user -> set of direct referrals, and one from user -> direct referrer.
- To reject a cycle when adding referrer -> referred, check whether referrer is already reachable from referred.
Part 2: Rank Users in a Referral DAG
Constraints
- 0 <= len(users) <= 500
- 0 <= len(referrals) <= 5000
- User IDs are strings and are distinct in the users list
- Duplicate edges may appear in input; treat them as one edge
- If the graph is not acyclic, return {'reach': [], 'flow': []}
Examples
Input: (['A', 'B', 'C', 'D'], [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D')], 3)
Expected Output: {'reach': [('A', 3), ('B', 1), ('C', 1)], 'flow': [('B', 1), ('C', 1), ('A', 0)]}
Explanation: A can reach B, C, and D. B and C each appear as an intermediate node in exactly one path.
Input: (['A', 'B', 'C'], [('A', 'B'), ('B', 'C')], 5)
Expected Output: {'reach': [('A', 2), ('B', 1), ('C', 0)], 'flow': [('B', 1), ('A', 0), ('C', 0)]}
Explanation: In the chain A -> B -> C, only B is an intermediate node on path A -> B -> C.
Input: (['A', 'B', 'C', 'D'], [('A', 'B')], 4)
Expected Output: {'reach': [('A', 1), ('B', 0), ('C', 0), ('D', 0)], 'flow': [('A', 0), ('B', 0), ('C', 0), ('D', 0)]}
Explanation: Edge case with isolated users and no intermediate nodes.
Input: ([], [], 2)
Expected Output: {'reach': [], 'flow': []}
Explanation: Empty network.
Input: (['A', 'B', 'C', 'D', 'E'], [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D'), ('D', 'E')], 2)
Expected Output: {'reach': [('A', 4), ('B', 2)], 'flow': [('D', 4), ('B', 2)]}
Explanation: D lies in four longer referral paths as an intermediate node; A reaches everyone else.
Hints
- For total reach in a DAG, process nodes in reverse topological order and accumulate descendant sets.
- For intermediate-node flow centrality, count how many paths end at a node from above and how many start from it below; multiplying those two counts gives the number of full paths where it is in the middle.
Part 3: Expected Referral Network Growth
Constraints
- 0 <= initial_users <= 10^6
- 0 <= days <= 10^5
- 0.0 <= p <= 1.0
- Each user can make at most 10 successful referrals over their lifetime
Examples
Input: (1, 0, 0.3)
Expected Output: 1.0
Explanation: Edge case: after 0 days, the network size is unchanged.
Input: (3, 10, 0.0)
Expected Output: 3.0
Explanation: If p = 0, nobody ever refers anyone.
Input: (1, 2, 0.5)
Expected Output: 2.25
Explanation: Expected births are 0.5 on day 1 and 0.75 on day 2, for a total expected size of 2.25.
Input: (2, 1, 0.25)
Expected Output: 2.5
Explanation: Two active users produce an expected 2 * 0.25 = 0.5 new users on day 1.
Input: (1, 11, 1.0)
Expected Output: 2047.0
Explanation: With p = 1, growth doubles each day until the original user hits the 10-referral lifetime cap; on day 11 only that original user is capped.
Hints
- Track 11 states: how many successful referrals a user has already made, from 0 to 10.
- By linearity of expectation, the expected number of users moving from state s to s+1 on a day is simply p * state[s].