Design Phone Directory

Updated on 22 May, 2025
Design Phone Directory header image

Problem Statement

The objective is to design a phone directory system where initially there are maxNumbers empty slots that can store phone numbers. Each slot can only store one phone number at a time.

The PhoneDirectory class should be able to:

  • Initialize the phone directory with a specified number of available slots.
  • Provide an unassigned number which isn't already given out.
  • Check the status of a specific slot (whether it is available or not).
  • Recycle or release a number back into the directory to make the slot available again.

For instance:

  • The constructor PhoneDirectory(int maxNumbers) sets up the directory with maxNumbers slots.
  • The method int get() returns the next available number, or -1 if no numbers are available.
  • The method bool check(int number) checks if a particular number is available (returns true) or not (returns false).
  • The method void release(int number) releases a previously assigned number, making it available again.

These functions ensure efficient management of available and assigned phone numbers within specified limits.

Examples

Example 1

Input

["PhoneDirectory", "get", "get", "check", "get", "check", "release", "check"]
[[3], [], [], [2], [], [2], [2], [2]]

Output

[null, 0, 1, true, 2, false, null, true]

Explanation

PhoneDirectory phoneDirectory = new PhoneDirectory(3);
phoneDirectory.get(); // It can return any available phone number. Here we assume it returns 0.
phoneDirectory.get(); // Assume it returns 1.
phoneDirectory.check(2); // The number 2 is available, so return true.
phoneDirectory.get(); // It returns 2, the only number that is left.
phoneDirectory.check(2); // The number 2 is no longer available, so return false.
phoneDirectory.release(2); // Release number 2 back to the pool.
phoneDirectory.check(2); // Number 2 is available again, return true.

Constraints

  • 1 <= maxNumbers <= 104
  • 0 <= number < maxNumbers
  • At most 2 * 104 calls will be made to get, check, and release.

Approach and Intuition

Understanding the Requirements:

  • The directory begins with all slots unassigned. Each slot corresponds to an integer from 0 to maxNumbers-1.
  • An available number is retrieved and marked as unavailable when get() is called.
  • We can check if a number is available using check(int number).
  • A number can be released (made available again) using release(int number).

Example Walk-through based on the given example:

  1. Initialization:

    • Instantiate the phone directory with 3 numbers. All numbers (0, 1, and 2) are initially available.
  2. Get Operations:

    • Call get(): Returns 0, the first available number. Now, the available numbers are 1 and 2.
    • Call get() again: Returns 1. Now, the only available number is 2.
  3. Check Operation:

    • Call check(2): Returns true since 2 is still available.
  4. Get Operation:

    • Call get(): Returns 2. Now, no numbers are left. All numbers (0, 1, and 2) are assigned.
  5. Check Operation:

    • Call check(2): Returns false since 2 is now assigned and not available.
  6. Release Operation:

    • Call release(2): This makes number 2 available again.
  7. Check Operation:

    • Call check(2): Returns true now since 2 is available again after release.

Structural Implementation Details:

  • Maintain a set or list to keep track of available numbers.
  • Utilize efficient data structures to ensure that operations like get, check, and release happen in reasonable time, especially given the constraints that up to 2 * 104 calls might be made.
  • Handling edge cases such as releasing an already available number or getting when no numbers are available are crucial to prevent errors.

Implementing the above methods with attention to performance while effectively managing available and assigned slots will provide a robust phone directory system.

Solutions

  • C++
  • Java
  • JavaScript
  • Python
cpp
class DirectoryService {
    unordered_set<int> availableNumbers;

public:
    DirectoryService(int maxNumbers) {
        for (int idx = 0; idx < maxNumbers; ++idx) {
            availableNumbers.insert(idx);
        }
    }

    int acquire() {
        if (availableNumbers.empty()) {
            return -1;
        }

        int num = *(availableNumbers.begin());
        availableNumbers.erase(num);
        return num;
    }

    bool isAvailable(int number) {
        return availableNumbers.find(number) != availableNumbers.end();
    }

    void free(int number) {
        availableNumbers.insert(number);
    }
};

The provided C++ program defines a class DirectoryService that simulates a phone directory service where numbers can be acquired, checked for availability, and released. Here's how the class operations work:

  • Constructor (DirectoryService(int maxNumbers)): Initializes the directory with a set of phone numbers ranging from 0 to maxNumbers - 1. Each number is inserted into an unordered set availableNumbers, making these numbers available for acquisition.

  • Acquire Method (int acquire()): Provides the first available phone number from the set. If no numbers are available (i.e., the set is empty), it returns -1 to indicate that no numbers can be acquired. It removes the acquired number from the availableNumbers set to ensure it is not issued again until it's released.

  • IsAvailable Method (bool isAvailable(int number)): Checks if a specific number is available for acquisition by searching for the number in availableNumbers. Returns true if the number exists in the set (is available), otherwise returns false.

  • Free Method (void free(int number)): Reinserts a previously acquired number back into the availableNumbers set, making it available for future acquisitions. This method effectively allows a number to be reused after it's released.

This design offers a straightforward mechanism for phone number management within a defined range, using set operations for efficiently handling the availability of numbers.

java
class ContactDirectory {
    private Set<Integer> availableSlots;

    public ContactDirectory(int maxNumbers) {
        availableSlots = new HashSet<>();
        for (int i = 0; i < maxNumbers; i++) {
            availableSlots.add(i);
        }
    }

    public int acquire() {
        if (availableSlots.isEmpty()) {
            return -1;
        }

        int acquiredNumber = availableSlots.iterator().next();
        availableSlots.remove(acquiredNumber);
        return acquiredNumber;
    }

    public boolean isAvailable(int number) {
        return availableSlots.contains(number);
    }

    public void free(int number) {
        availableSlots.add(number);
    }
}

The given Java code implements a class named ContactDirectory that manages a phone directory, enabling you to acquire, check availability, and free up phone numbers. Here's how the class is structured and operates:

  • Initialize ContactDirectory with a specified number of maximum available phone numbers. This is done through the constructor which accepts maxNumbers. It uses a HashSet to track and store all available phone numbers from 0 up to maxNumbers - 1.

  • The acquire method allows you to request a phone number. If numbers are available, it retrieves and removes a number from the set of available numbers and returns it. If no numbers are available, it returns -1.

  • The isAvailable method checks if a specific number is available within the directory. Returns true if the number is still in the set of available numbers, indicating it hasn't been acquired yet, and false otherwise.

  • The free method releases a previously acquired number back to the directory, making it available again for acquisition.

This implementation ensures efficient management of phone numbers in a directory, using Java's Set data structure to handle operations with good performance for adding, checking, and removing elements.

js
var DirectoryService = function(maxNumbers) {
    this.availableNumbers = new Set([...Array(maxNumbers).keys()]);
};

DirectoryService.prototype.obtain = function() {
    if (this.availableNumbers.size === 0) {
        return -1;
    }
    const num = this.availableNumbers.values().next().value;
    this.availableNumbers.delete(num);
    return num;
};

DirectoryService.prototype.isPresent = function(number) {
    return this.availableNumbers.has(number);
};

DirectoryService.prototype.free = function(number) {
    this.availableNumbers.add(number);
};

The solution provided outlines an implementation of a phone directory management system in JavaScript. Here’s how each part of the code works and their functions:

  1. The DirectoryService function constructs an object where a set called availableNumbers stores all the potential phone numbers that can be assigned. The numbers range from 0 to maxNumbers - 1.

  2. DirectoryService.prototype.obtain allows for fetching and removing the first available number from the set. If no numbers are available, it returns -1. This ensures that once a number is obtained, it’s no longer available in the directory until released.

  3. DirectoryService.prototype.isPresent checks whether a particular number is still available in the directory. It returns a boolean indicating the presence of the number in the set availableNumbers.

  4. Lastly, the DirectoryService.prototype.free method adds a number back to the set, making it available again for allocation. This is particularly useful for recycling or reusing numbers that were previously in use but are now free.

This structure supports basic operations required for managing a pool of phone numbers efficiently, ensuring that there are no duplicates in active usage and numbers can be easily recycled. The use of JavaScript's Set provides an efficient way of handling the uniqueness and order of numbers.

python
class DirectoryService:
    def __init__(self, max_slots):
        self.available_slots = set(range(max_slots))

    def acquire(self):
        if not self.available_slots:
            return -1
        return self.available_slots.pop()

    def is_available(self, slot):
        return slot in self.available_slots

    def free_up(self, slot):
        self.available_slots.add(slot)

This Python solution outlines a simple approach to designing a phone directory service. The solution uses a class DirectoryService that manages the availability of phone numbers using a set data structure to store vacant slots for efficient access and manipulation.

  • Initialize the Directory Service with a specified maximum number of available slots using the __init__ method. This sets up all slots as initially available.
  • Use the acquire method to allocate an available slot. If no slots are available, the method returns -1.
  • Implement the is_available method to check if a specific slot is currently available. It returns a boolean.
  • Define the free_up method to release a slot that is no longer in use, adding it back to the set of available slots.

This approach ensures that acquiring and freeing up slots are operations that can be performed efficiently, and checking slot availability is straightforward.

Comments

No comments yet.