Watch 10 video solutions for Design a Number Container System, a medium level problem involving Hash Table, Design, Heap (Priority Queue). This walkthrough by codestorywithMIK has 7,690 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
Design a number container system that can do the following:
Implement the NumberContainers class:
NumberContainers() Initializes the number container system.void change(int index, int number) Fills the container at index with the number. If there is already a number at that index, replace it.int find(int number) Returns the smallest index for the given number, or -1 if there is no index that is filled by number in the system.
Example 1:
Input ["NumberContainers", "find", "change", "change", "change", "change", "find", "change", "find"] [[], [10], [2, 10], [1, 10], [3, 10], [5, 10], [10], [1, 20], [10]] Output [null, -1, null, null, null, null, 1, null, 2] Explanation NumberContainers nc = new NumberContainers(); nc.find(10); // There is no index that is filled with number 10. Therefore, we return -1. nc.change(2, 10); // Your container at index 2 will be filled with number 10. nc.change(1, 10); // Your container at index 1 will be filled with number 10. nc.change(3, 10); // Your container at index 3 will be filled with number 10. nc.change(5, 10); // Your container at index 5 will be filled with number 10. nc.find(10); // Number 10 is at the indices 1, 2, 3, and 5. Since the smallest index that is filled with 10 is 1, we return 1. nc.change(1, 20); // Your container at index 1 will be filled with number 20. Note that index 1 was filled with 10 and then replaced with 20. nc.find(10); // Number 10 is at the indices 2, 3, and 5. The smallest index that is filled with 10 is 2. Therefore, we return 2.
Constraints:
1 <= index, number <= 109105 calls will be made in total to change and find.Problem Overview: You need to design a data structure that supports two operations: change(index, number) which assigns a number to an index, and find(number) which returns the smallest index currently storing that number. The challenge is handling frequent updates while always retrieving the minimum index efficiently.
Approach 1: HashMap + Ordered Set (O(log n) per operation)
Maintain two structures: a hash map indexToNumber that records the current number stored at each index, and another map numberToIndices where each number points to an ordered set of indices. When change(index, number) is called, check if the index already holds a value. If it does, remove that index from the ordered set of the previous number. Then insert the index into the ordered set of the new number and update indexToNumber. The find(number) operation simply returns the smallest element from the ordered set (e.g., TreeSet.first()). Insertions and removals in the ordered set cost O(log n), while lookups in the hash map are O(1). Space complexity is O(n). This approach relies heavily on hash tables and an ordered set structure.
Approach 2: Two HashMaps + Min Heap with Lazy Cleanup (O(log n) amortized)
Instead of maintaining a perfectly clean ordered set, store indices for each number in a min heap. Use indexToNumber to track the latest value assigned to each index, and numberToHeap where each number maps to a min heap of indices. Every time change(index, number) runs, push the index into the heap for that number and update indexToNumber. Old entries are not removed immediately. During find(number), repeatedly check the heap's top element. If the index at the top no longer maps to that number in indexToNumber, discard it. Continue until a valid index appears or the heap becomes empty. Each heap push or pop costs O(log n), and lazy deletion keeps updates simple. Total space complexity remains O(n). This method uses hash tables and a heap (priority queue).
Recommended for interviews: The ordered set solution is the cleanest and easiest to reason about. Interviewers like it because every structure always stays consistent and each operation has a clear O(log n) bound. The heap-based approach is also acceptable and commonly used in languages without a built-in ordered set. Showing both demonstrates strong understanding of data structure design and tradeoffs between strict ordering and lazy cleanup strategies.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| HashMap + Ordered Set | O(log n) per operation | O(n) | Best when language supports TreeSet/SortedSet for direct smallest-index lookup |
| Two HashMaps + Min Heap (Lazy Deletion) | O(log n) amortized | O(n) | Useful in languages without ordered sets; heap cleanup happens during queries |