Resolve user roles across account hierarchy
Company: TikTok
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of hierarchical data structures, role-based access control semantics, and set/map operations for computing effective permissions across account ancestors in the Coding & Algorithms domain.
Part 1: Get direct roles for a user on an account
Constraints
- 0 <= len(user_role_assignments) <= 100000
- Each assignment contains 'userId', 'accountId', and 'role' as strings
- Duplicate assignments may exist and must be deduplicated in the returned set
Examples
Input: ([{'userId': 'u1', 'accountId': 'a1', 'role': 'admin'}, {'userId': 'u1', 'accountId': 'a1', 'role': 'billing'}, {'userId': 'u1', 'accountId': 'a2', 'role': 'viewer'}, {'userId': 'u2', 'accountId': 'a1', 'role': 'admin'}], 'u1', 'a1')
Expected Output: {'admin', 'billing'}
Explanation: Only the first two assignments match both user 'u1' and account 'a1'.
Input: ([{'userId': 'u1', 'accountId': 'a1', 'role': 'admin'}, {'userId': 'u1', 'accountId': 'a1', 'role': 'admin'}, {'userId': 'u1', 'accountId': 'a2', 'role': 'billing'}, {'userId': 'u2', 'accountId': 'a1', 'role': 'admin'}], 'u1', 'a1')
Expected Output: {'admin'}
Explanation: The same role is assigned twice on the same account, but the result must contain unique roles only.
Input: ([], 'u1', 'a1')
Expected Output: set()
Explanation: With no assignments, there are no roles to return.
Input: ([{'userId': 'u1', 'accountId': 'a2', 'role': 'admin'}, {'userId': 'u2', 'accountId': 'a1', 'role': 'billing'}], 'u1', 'a1')
Expected Output: set()
Explanation: One assignment has the right user but wrong account, and the other has the right account but wrong user.
Input: ([{'userId': 'u9', 'accountId': 'acct', 'role': 'viewer'}], 'u9', 'acct')
Expected Output: {'viewer'}
Explanation: There is exactly one matching assignment, so its role is returned.
Hints
- A single pass through the assignments is enough.
- Use a set so duplicate role assignments collapse automatically.
Part 2: Get effective roles for a user including ancestor accounts
Constraints
- 1 <= len(accounts) <= 100000
- 0 <= len(user_role_assignments) <= 100000
- The accounts form a forest with no cycles
- account_id may be assumed to be a valid account in the hierarchy
- Duplicate assignments may exist and must be deduplicated in the returned set
Examples
Input: ([('root', None), ('eng', 'root'), ('ops', 'root')], [('u1', 'eng', 'admin'), ('u1', 'eng', 'editor'), ('u1', 'root', 'viewer'), ('u2', 'eng', 'admin')], 'u1', 'eng')
Expected Output: ['admin', 'editor']
Explanation: Only direct assignments on 'eng' for user 'u1' count. The role on 'root' is ignored in Part 1.
Input: ([('root', None), ('team', 'root')], [('u1', 'team', 'viewer'), ('u1', 'team', 'viewer'), ('u1', 'team', 'admin')], 'u1', 'team')
Expected Output: ['admin', 'viewer']
Explanation: Duplicate 'viewer' assignments should appear only once.
Input: ([('root', None), ('child', 'root')], [('u1', 'root', 'admin'), ('u1', 'other', 'editor')], 'u1', 'child')
Expected Output: []
Explanation: There is no direct assignment for 'u1' on 'child'. Roles on ancestors or other accounts do not count here.
Input: ([('solo', None)], [], 'u1', 'solo')
Expected Output: []
Explanation: Edge case: no assignments at all.
Hints
- First build a map from accountId to parent.
- Walk upward from the target account to collect all ancestor account IDs, then scan assignments.
Part 3: Get all users effective on an account with inherited roles
Constraints
- 1 <= len(accounts) <= 100000
- 0 <= len(user_role_assignments) <= 100000
- The account hierarchy is a forest with no cycles
- account_id may be assumed to be a valid account
- Duplicate assignments may exist and should be deduplicated in each user's role set
Examples
Input: ([('acc_root', None), ('acc_dept', 'acc_root'), ('acc_team', 'acc_dept')], [('usr_1', 'admin', 'acc_root'), ('usr_1', 'billing', 'acc_dept'), ('usr_2', 'viewer', 'acc_team'), ('usr_2', 'viewer', 'acc_team')], 'acc_team')
Expected Output: {'usr_1': {'admin', 'billing'}, 'usr_2': {'viewer'}}
Explanation: The target account inherits roles from itself, its parent, and the root. The duplicate viewer assignment for usr_2 is deduplicated.
Input: ([('acc_root', None), ('acc_child', 'acc_root')], [('usr_1', 'admin', 'acc_root'), ('usr_2', 'viewer', 'acc_child')], 'acc_root')
Expected Output: {'usr_1': {'admin'}}
Explanation: Roles do not flow upward. usr_2 has a role only on the child account, so it is not effective on the root.
Input: ([('root', None), ('engineering', 'root'), ('finance', 'root'), ('platform', 'engineering')], [('usr_2', 'viewer', 'finance'), ('usr_1', 'editor', 'engineering'), ('usr_1', 'editor', 'root'), ('usr_1', 'editor', 'root'), ('usr_3', 'auditor', 'platform')], 'platform')
Expected Output: {'usr_1': {'editor'}, 'usr_3': {'auditor'}}
Explanation: Only roles from platform, engineering, and root are effective on platform. The finance role is on a sibling branch and is ignored. Duplicate editor assignments collapse to one role.
Input: ([('solo', None)], [], 'solo')
Expected Output: {}
Explanation: There are no assignments, so no user has an effective role.
Input: ([('acct', None)], [('usr_2', 'viewer', 'acct'), ('usr_1', 'billing', 'acct'), ('usr_1', 'admin', 'acct')], 'acct')
Expected Output: {'usr_1': {'admin', 'billing'}, 'usr_2': {'viewer'}}
Explanation: Both direct roles for usr_1 are included, and the dictionary is built with user ids inserted in sorted order.
Hints
- Find the target account's ancestor chain first.
- Then group assignments by user, but only if the assignment's account lies on that chain.
Part 4: Filter users on an account by required effective roles
Constraints
- 1 <= len(accounts) <= 100000
- 0 <= len(user_role_assignments) <= 100000
- 0 <= len(roles_filter) <= 1000
- The account hierarchy is a forest with no cycles
- account_id may be assumed to be valid
- roles_filter may contain duplicates; they do not change the answer
Examples
Input: ([('acc_root', None), ('acc_eng', 'acc_root'), ('acc_team', 'acc_eng'), ('acc_sales', 'acc_root')], [('usr_1', 'reader', 'acc_root'), ('usr_1', 'editor', 'acc_eng'), ('usr_2', 'reader', 'acc_team'), ('usr_3', 'editor', 'acc_root'), ('usr_4', 'reader', 'acc_sales')], 'acc_team', ['reader', 'editor'])
Expected Output: ['usr_1']
Explanation: On acc_team, usr_1 has reader from acc_root and editor from acc_eng, so usr_1 satisfies both required roles. usr_2 has only reader, usr_3 has only editor, and usr_4 is on a different branch.
Input: ([('acc_root', None), ('acc_eng', 'acc_root'), ('acc_team', 'acc_eng'), ('acc_sales', 'acc_root')], [('usr_2', 'billing', 'acc_root'), ('usr_1', 'viewer', 'acc_team'), ('usr_1', 'viewer', 'acc_team'), ('usr_3', 'admin', 'acc_eng'), ('usr_4', 'viewer', 'acc_sales')], 'acc_team', [])
Expected Output: ['usr_1', 'usr_2', 'usr_3']
Explanation: An empty roles_filter means return every user with at least one effective role on acc_team. usr_1, usr_2, and usr_3 all have effective roles there. The duplicate viewer assignment for usr_1 is deduplicated.
Input: ([('acc_root', None)], [('usr_a', 'ops', 'acc_root'), ('usr_a', 'ops', 'acc_root'), ('usr_b', 'ops', 'acc_root'), ('usr_b', 'audit', 'acc_root')], 'acc_root', ['ops', 'ops'])
Expected Output: ['usr_a', 'usr_b']
Explanation: Duplicate assignments do not change the effective role set, and duplicate entries in roles_filter still only require the role 'ops' once.
Input: ([('acc_root', None), ('acc_child', 'acc_root')], [('usr_1', 'viewer', 'acc_root')], 'acc_child', ['admin'])
Expected Output: []
Explanation: usr_1 has viewer on acc_root, which is effective on acc_child, but no user has the required admin role.
Input: ([('acc_root', None)], [], 'acc_root', [])
Expected Output: []
Explanation: There are no assignments at all, so no user has any effective role on the target account.
Input: ([('acc_root', None), ('acc_child', 'acc_root'), ('acc_grand', 'acc_child')], [('usr_1', 'editor', 'acc_grand'), ('usr_2', 'editor', 'acc_root')], 'acc_child', ['editor'])
Expected Output: ['usr_2']
Explanation: A role assigned on a descendant does not flow upward. usr_1's editor role on acc_grand is not effective on acc_child, but usr_2's editor role on acc_root is.
Hints
- This part becomes easier if you first compute each user's effective role set on the target account.
- Checking whether a user qualifies is a subset test between roles_filter and that user's role set.