Implement Several Core Algorithmic Components
Company: WeRide
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This multi-part problem evaluates core competencies in data structures and algorithm design (LRU cache, grid pathfinding and earliest-feasible-time analysis), randomized algorithms and probability (rand7→rand10 and reservoir sampling), and computational geometry with counting and hashing for axis-aligned square detection.
Part 1: Implement an LRU Cache
Constraints
- 1 <= capacity <= 10^5
- 1 <= len(op_types) == len(args) <= 2 * 10^5
- 0 <= key, value <= 10^9
- Both 'get' and 'put' should be handled in O(1) average time per operation
Examples
Input: (2, ['put', 'put', 'get', 'put', 'get', 'put', 'get', 'get', 'get'], [[1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]])
Expected Output: [1, -1, -1, 3, 4]
Explanation: After inserting 1 and 2, getting 1 makes it most recent. Putting 3 evicts 2, and putting 4 later evicts 1.
Input: (1, ['put', 'put', 'get', 'get'], [[1, 10], [2, 20], [1], [2]])
Expected Output: [-1, 20]
Explanation: With capacity 1, inserting key 2 evicts key 1.
Input: (2, ['put', 'put', 'put', 'get', 'put', 'get', 'get'], [[2, 1], [2, 2], [1, 1], [2], [4, 1], [1], [2]])
Expected Output: [2, -1, 2]
Explanation: Updating an existing key should not increase cache size and should refresh its recency.
Hints
- A hash map can find a key in O(1), but you also need O(1) updates to recency order.
- A doubly linked list is a good way to remove and insert nodes in O(1) when combined with a hash map.
Part 2: Find the Earliest Feasible Time to Cross a Grid
Constraints
- 1 <= len(grid) <= 200
- 1 <= len(grid[0]) <= 200
- 0 <= grid[r][c] <= 10^9
Examples
Input: [[0, 2], [1, 3]]
Expected Output: 3
Explanation: You must wait until time 3 before a complete path exists.
Input: [[0, 1, 2, 3, 4], [24, 23, 22, 21, 5], [12, 13, 14, 15, 16], [11, 17, 18, 19, 20], [10, 9, 8, 7, 6]]
Expected Output: 16
Explanation: The optimal route keeps the maximum required cell value at 16.
Input: [[7]]
Expected Output: 7
Explanation: The start is also the destination, so the answer is the cell's own availability time.
Input: [[0, 100], [1, 2]]
Expected Output: 2
Explanation: Going down first avoids waiting for the cell with value 100.
Hints
- Think of the cost of a path as the maximum grid value seen along that path.
- Dijkstra's algorithm works if the distance to a cell is defined as the minimum possible maximum value needed to reach it.
Part 3: Generate rand10() Using rand7()
Constraints
- 0 <= k <= 10^5
- 0 <= len(rolls) <= 2 * 10^5
- Each value in rolls is between 1 and 7
Examples
Input: ([1, 1, 2, 7, 6, 6, 1, 5], 3)
Expected Output: [1, 4, 5]
Explanation: Pairs (1,1) and (2,7) are accepted immediately. Pair (6,6) gives 41 and is rejected, so the next pair (1,5) produces 5.
Input: ([1, 2, 3, 4], 0)
Expected Output: []
Explanation: Requesting zero outputs should return an empty list.
Input: ([7, 7, 7, 6, 7, 5, 3, 4], 1)
Expected Output: [8]
Explanation: 49, 48, and 47 are rejected. The next accepted value is 18, which maps to 8.
Input: ([6, 5, 1, 1, 1, 7], 2)
Expected Output: [10, 1]
Explanation: 40 maps to 10, and then 1 maps to 1.
Hints
- Two independent rand7() calls give 49 equally likely outcomes.
- Only the first 40 outcomes can be evenly mapped onto 10 results.
Part 4: Design a Data Structure for Counting Axis-Aligned Squares
Constraints
- 1 <= len(op_types) == len(points) <= 5000
- -10^4 <= x, y <= 10^4
- Duplicate points may be added multiple times
Examples
Input: (['add', 'add', 'add', 'count', 'count', 'add', 'count'], [[3, 10], [11, 2], [3, 2], [11, 10], [14, 8], [11, 2], [11, 10]])
Expected Output: [1, 0, 2]
Explanation: The first query forms one square. After adding a duplicate point at (11,2), the same square can be formed in two distinct ways.
Input: (['count'], [[0, 0]])
Expected Output: [0]
Explanation: With no added points, there are no squares.
Input: (['add', 'add', 'add', 'add', 'add', 'count', 'count'], [[0, 0], [1, 0], [0, 1], [1, 1], [1, 1], [0, 0], [1, 0]])
Expected Output: [2, 2]
Explanation: The duplicate point (1,1) doubles the number of valid squares for both queries.
Hints
- For a query point, any square partner on the same horizontal line determines the side length.
- Store point multiplicities so duplicates contribute multiple valid squares.
Part 5: Explain and Implement Reservoir Sampling
Constraints
- 0 <= len(stream) == len(draws) <= 2 * 10^5
- 0 <= stream[i] <= 10^9
- For each i, draws[i] is an integer in the range [1, i + 1]
Examples
Input: ([10, 20, 30, 40], [1, 2, 1, 3])
Expected Output: 30
Explanation: 10 is chosen first, 20 is ignored, 30 replaces it, and 40 is ignored.
Input: ([], [])
Expected Output: -1
Explanation: An empty stream has no selectable item.
Input: ([7], [1])
Expected Output: 7
Explanation: With one item, that item must be selected.
Input: ([5, 6, 7, 8, 9], [1, 1, 3, 1, 5])
Expected Output: 8
Explanation: 5 is chosen, then replaced by 6, kept through 7, replaced by 8, and kept through 9.
Hints
- At step i, the new item should become the sample with probability 1 / i.
- To prove uniformity, show that after processing i items, every item has probability 1 / i of being stored.