379. Design Phone Directory
Design a Phone Directory which supports the following operations:
get
: Provide a number which is not assigned to anyone.check
: Check if a number is available or not.release
: Recycle or release a number.
Example:
// Init a phone directory containing a total of 3 numbers: 0, 1, and 2.
PhoneDirectory directory = new PhoneDirectory(3);
// It can return any available phone number. Here we assume it returns 0.
directory.get();
// Assume it returns 1.
directory.get();
// The number 2 is available, so return true.
directory.check(2);
// It returns 2, the only number that is left.
directory.get();
// The number 2 is no longer available, so return false.
directory.check(2);
// Release number 2 back to the pool.
directory.release(2);
// Number 2 is available again, return true.
directory.check(2);
State the problem (as you understand it):
Solve examples that are big enough and are not special cases (manually to figure out the general solution):
Ask clarification questions:
- what is the frequency of get() and release() calls?
- optimize for time or space?
State assumptions:
- get() and release() calls happen at the same frequency
Consider several test cases (edge cases, base cases):
See if a Data Structure fits the problem:
See if an Algorithm fits the problem:
Extract the core problem:
Try breaking it down into subproblems:
Explain Potential Solutions (see solutin section):
Other solutions:
Compare solutions:
Follow Up (TODO):
- how scalable this solution is if we are talking about 10 digit real phone number?
- probably expect some discussion of distributed hash tables
- what happens if it is being used in multithreaded situation?
Solution 1:
Ideas:
- not necessary to store both used and unused numbers, just keep track of the unused ones to save memory
- keep track of the largest number offered so far to avoid O(n) initialization for available numbers. Anything above the largest number offered so far is available for offering
- exhaust the sparse set of available numbers first if it's not empty
Steps:
Validate the correctness (of your pseudocode with a test case):
Data Structure:
Time Complexity:
Space Complexity:
public class PhoneDirectory {
private final Set<Integer> available = new LinkedHashSet<>();
private final int maxNumbers;
private int largestOffered = -1;
public PhoneDirectory(int maxNumbers) {
this.maxNumbers = maxNumbers;
}
public int get() {
if (this.available.isEmpty()) {
return this.largestOffered < this.maxNumbers - 1 ? (++this.largestOffered) : -1;
}
Iterator<Integer> iterator = this.available.iterator();
int res = iterator.next();
iterator.remove();
return res;
}
public boolean check(int number) {
return this.available.contains(number) || number > this.largestOffered && number < this.maxNumbers;
}
public void release(int number) {
if (number <= this.largestOffered) {
this.available.add(number);
}
}
}
Test your code again to make sure you don't have any bugs.