Coding questions · eBay
Solve Dependency, Prefix, and Cache Problems
This set of problems evaluates graph algorithms for dependency and cycle detection, efficient data structure design for prefix-based word storage, and cache eviction policy implementation, assessing skills in algorithmic analysis, data structures, and time/space complexity within the Coding & Algorithms domain.
Solve the following three coding problems.
Problem 1: Determine Whether All Tasks Can Be Completed
You are given numTasks, the number of tasks labeled from 0 to numTasks - 1, and a list of prerequisite pairs prerequisites. Each pair [a, b] means task b must be completed before task a.
Return true if it is possible to complete all tasks. Return false if the prerequisite graph contains a cycle.
Example:
numTasks = 2
prerequisites = [[1, 0]]
Output: true
numTasks = 2
prerequisites = [[1, 0], [0, 1]]
Output: false
Problem 2: Implement a Prefix-Based Word Store
Design a data structure that supports the following operations:
insert(word): Add a lowercase English word.search(word): Return whether the exact word exists.startsWith(prefix): Return whether any inserted word starts with the given prefix.
All inputs contain only lowercase English letters a through z.
Example:
insert("apple")
search("apple") -> true
search("app") -> false
startsWith("app") -> true
insert("app")
search("app") -> true
Problem 3: Implement a Fixed-Capacity Least-Recently-Used Cache
Design a cache with positive integer capacity that supports:
get(key): Return the value associated withkeyif it exists; otherwise return-1. Accessing a key makes it the most recently used item.put(key, value): Insert or update the value forkey. If the cache exceeds capacity, evict the least recently used item.
Both operations should run in average O(1) time.
Example:
capacity = 2
put(1, 1)
put(2, 2)
get(1) -> 1
put(3, 3) // evicts key 2
get(2) -> -1
put(4, 4) // evicts key 1
get(1) -> -1
get(3) -> 3
get(4) -> 4
Part 1: Determine Whether All Tasks Can Be Completed
Given an integer numTasks and a list of prerequisite pairs prerequisites, where each pair [a, b] means task b must be completed before task a, determine whether it is possible to finish every task. Return True if the prerequisite graph contains no cycle; otherwise return False.
Constraints
- 0 <= numTasks <= 100000
- 0 <= len(prerequisites) <= 200000
- Each prerequisite is a pair [a, b] with 0 <= a, b < numTasks
Examples
Example 1
Input: (2, [[1, 0]])
Output: True
Explanation: Task 0 can be done first, then task 1. There is no cycle.
Example 2
Input: (2, [[1, 0], [0, 1]])
Output: False
Explanation: Task 0 depends on task 1 and task 1 depends on task 0, forming a cycle.
Hints
- Model the tasks as a directed graph and look for a way to detect cycles.
- If you repeatedly remove tasks with indegree 0 and cannot process all tasks, a cycle must exist.
Part 2: Implement a Prefix-Based Word Store
Implement a prefix-based word store using a function interface. The function receives a list of operations. Each operation is a tuple (op, text), where op is one of 'insert', 'search', or 'startsWith'. For each 'insert', append None to the output list. For each 'search' or 'startsWith', append the boolean result. Return the full result list in operation order.
Constraints
- 0 <= len(operations) <= 20000
- Each word or prefix has length between 1 and 2000
- The sum of lengths of all words and prefixes is at most 200000
- All characters are lowercase English letters a through z
Examples
Example 1
Input: [('insert', 'apple'), ('search', 'apple'), ('search', 'app'), ('startsWith', 'app'), ('insert', 'app'), ('search', 'app')]
Output: [None, True, False, True, None, True]
Explanation: 'apple' is inserted first. Exact search for 'apple' is True, exact search for 'app' is False until 'app' is inserted, while startsWith('app') is already True because 'apple' starts with it.
Example 2
Input: [('search', 'dog'), ('startsWith', 'do')]
Output: [False, False]
Explanation: No words have been inserted yet, so both the exact search and prefix check return False.
Hints
- A trie stores one character per level and is a natural fit for both exact word checks and prefix checks.
- Exact search and prefix search traverse similarly; only exact search must verify an end-of-word marker.
Part 3: Implement a Fixed-Capacity Least-Recently-Used Cache
Simulate an LRU cache using a function interface. The function receives a positive integer capacity and a list of operations. Each operation is either ('put', key, value) or ('get', key). Return a list aligned with the operations: append None for each put, and append the returned integer for each get. Accessing or updating a key makes it the most recently used item. When the cache exceeds capacity, evict the least recently used key.
Constraints
- 1 <= capacity <= 30000
- 0 <= len(operations) <= 200000
- 0 <= key <= 1000000000
- 0 <= value <= 1000000000
Examples
Example 1
Input: (2, [('put', 1, 1), ('put', 2, 2), ('get', 1), ('put', 3, 3), ('get', 2), ('put', 4, 4), ('get', 1), ('get', 3), ('get', 4)])
Output: [None, None, 1, None, -1, None, -1, 3, 4]
Explanation: After getting key 1, it becomes most recently used. Putting 3 evicts 2. Putting 4 later evicts 1.
Example 2
Input: (1, [('put', 2, 1), ('put', 3, 2), ('get', 2), ('get', 3), ('put', 4, 3), ('get', 4)])
Output: [None, None, -1, 2, None, 3]
Explanation: With capacity 1, each new key evicts the previous one. Key 2 is gone after putting 3, and key 3 is gone after putting 4.
Hints
- Use a hash map for O(1) access to cache entries and a doubly linked list to track recency order.
- Move a key to the front whenever it is read or updated, and remove from the tail when eviction is needed.