{x}
blog image

Design Phone Directory

Solution Explanation: Design Phone Directory

This problem requires designing a phone directory data structure that efficiently handles three operations: getting an available phone number, checking if a number is available, and releasing a phone number back to the pool. The optimal approach leverages a HashSet (or Set in other languages) to track available phone numbers.

Data Structure:

A HashSet (or equivalent) is ideal because it provides:

  • Constant-time average complexity for insertion, deletion, and lookup: These are the core operations needed for get, check, and release.
  • Uniqueness: Ensures we don't accidentally assign the same number twice.

Algorithm:

  1. __init__ (Constructor): Initializes the HashSet (available) with all phone numbers from 0 to maxNumbers - 1. This represents the initial pool of available numbers.

  2. get():

    • Checks if the HashSet is empty. If it is, no numbers are available, so it returns -1.
    • If numbers are available, it retrieves any element from the HashSet (the order doesn't matter). Many languages' Set implementations offer efficient ways to get an arbitrary element (e.g., using an iterator).
    • The retrieved number is removed from the HashSet to indicate it's now assigned.
    • The number is returned.
  3. check():

    • Simply checks if the given number is present in the HashSet. Returns true if it's available (in the set), and false otherwise.
  4. release():

    • Adds the given number back to the HashSet, making it available for future allocation.

Time and Space Complexity:

  • Time Complexity:

    • get(): O(1) on average (can be O(n) in the worst case for some implementations of Set, but this is unlikely with a well-designed hash set).
    • check(): O(1) on average.
    • release(): O(1) on average.
    • Constructor: O(n), where n is maxNumbers, to populate the set initially.
  • Space Complexity: O(n), where n is maxNumbers. This is because the HashSet stores up to maxNumbers elements.

Code Examples (with detailed explanations inline):

The code examples provided previously demonstrate the implementation of this algorithm in various programming languages. The key data structure is always a HashSet (or its equivalent), and the operations directly map to the algorithm steps described above. For instance, in Python, available.pop() efficiently removes and returns an arbitrary element. In Java, available.iterator().next() achieves a similar outcome, as does available.begin() in C++. Each language's set implementation is optimized for efficient average-case performance.