You have an infinite number of stacks arranged in a row and numbered (left to right) from 0, each of the stacks has the same maximum capacity.
Implement the DinnerPlates class:
DinnerPlates(int capacity) Initializes the object with the maximum capacity of the stacks capacity.void push(int val) Pushes the given integer val into the leftmost stack with a size less than capacity.int pop() Returns the value at the top of the rightmost non-empty stack and removes it from that stack, and returns -1 if all the stacks are empty.int popAtStack(int index) Returns the value at the top of the stack with the given index index and removes it from that stack or returns -1 if the stack with that given index is empty.Example 1:
Input
["DinnerPlates", "push", "push", "push", "push", "push", "popAtStack", "push", "push", "popAtStack", "popAtStack", "pop", "pop", "pop", "pop", "pop"]
[[2], [1], [2], [3], [4], [5], [0], [20], [21], [0], [2], [], [], [], [], []]
Output
[null, null, null, null, null, null, 2, null, null, 20, 21, 5, 4, 3, 1, -1]
Explanation:
DinnerPlates D = DinnerPlates(2); // Initialize with capacity = 2
D.push(1);
D.push(2);
D.push(3);
D.push(4);
D.push(5); // The stacks are now: 2 4
1 3 5
﹈ ﹈ ﹈
D.popAtStack(0); // Returns 2. The stacks are now: 4
1 3 5
﹈ ﹈ ﹈
D.push(20); // The stacks are now: 20 4
1 3 5
﹈ ﹈ ﹈
D.push(21); // The stacks are now: 20 4 21
1 3 5
﹈ ﹈ ﹈
D.popAtStack(0); // Returns 20. The stacks are now: 4 21
1 3 5
﹈ ﹈ ﹈
D.popAtStack(2); // Returns 21. The stacks are now: 4
1 3 5
﹈ ﹈ ﹈
D.pop() // Returns 5. The stacks are now: 4
1 3
﹈ ﹈
D.pop() // Returns 4. The stacks are now: 1 3
﹈ ﹈
D.pop() // Returns 3. The stacks are now: 1
﹈
D.pop() // Returns 1. There are no stacks.
D.pop() // Returns -1. There are still no stacks.
Constraints:
1 <= capacity <= 2 * 1041 <= val <= 2 * 1040 <= index <= 1052 * 105 calls will be made to push, pop, and popAtStack.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We need to simulate a collection of stacks that act like dinner plates, where each stack has a limited capacity. The brute force approach simply tries to perform each push and pop operation as requested, checking all possible stacks to find the correct one.
Here's how the algorithm would work step-by-step:
class DinnerPlates:
def __init__(self, capacity: int):
self.capacity = capacity
self.stacks_list = []
def push(self, val: int) -> None:
# Iterate through the stacks to find the first non-full stack
for stack in self.stacks_list:
if len(stack) < self.capacity:
stack.append(val)
return
# If all stacks are full, create a new stack.
self.stacks_list.append([val])
def pop(self) -> int:
# Iterate through the stacks from right to left.
for i in range(len(self.stacks_list) - 1, -1, -1):
if self.stacks_list[i]:
return self.stacks_list[i].pop()
# If all stacks are empty, return -1.
return -1
def popAtStack(self, index: int) -> int:
# Check if the index is valid
if 0 <= index < len(self.stacks_list) and self.stacks_list[index]:
# If the stack isn't empty, pop the top element.
return self.stacks_list[index].pop()
else:
# If the stack is empty or index invalid, return -1.
return -1Imagine managing stacks of plates where you want to keep adding and removing plates efficiently. The trick is to keep track of where you have space to add plates and where you can easily remove them, avoiding full or empty stacks as much as possible.
Here's how the algorithm would work step-by-step:
class DinnerPlates:
def __init__(self, capacity: int):
self.capacity = capacity
self.stacks = []
self.available_stacks = []
def push(self, value: int) -> None:
# Find an available stack or create a new one
if self.available_stacks:
index_to_use = self.available_stacks[0]
self.stacks[index_to_use].append(value)
if len(self.stacks[index_to_use]) == self.capacity:
self.available_stacks.pop(0)
else:
self.stacks.append([value])
if len(self.stacks[-1]) < self.capacity:
self.available_stacks.append(len(self.stacks) - 1)
def pop(self) -> int:
# Pop from the rightmost non-empty stack
while self.stacks and not self.stacks[-1]:
self.stacks.pop()
if not self.stacks:
return -1
value_to_return = self.stacks[-1].pop()
if len(self.stacks[-1]) == 0:
self.stacks.pop()
# Re-add to available stacks if applicable
if self.stacks and len(self.stacks[-1]) < self.capacity:
if not self.available_stacks or self.available_stacks[-1] != len(self.stacks) -1:
self.available_stacks.append(len(self.stacks) - 1)
self.available_stacks.sort()
return value_to_return
def popAtStack(self, index: int) -> int:
if index >= len(self.stacks) or not self.stacks[index]:
return -1
value_to_return = self.stacks[index].pop()
# Keep track of available stack
if index not in self.available_stacks:
self.available_stacks.append(index)
self.available_stacks.sort()
# Clean up trailing empty stacks
while self.stacks and not self.stacks[-1]:
self.stacks.pop()
return value_to_return
# Your DinnerPlates object will be instantiated and called as such:
# dinner_plates_object = DinnerPlates(capacity)
# dinner_plates_object.push(value)
# value_popped = dinner_plates_object.pop()
# value_popped_at_stack = dinner_plates_object.popAtStack(index)| Case | How to Handle |
|---|---|
| pushing to a full stack | The algorithm should create a new stack if the current stack is full, adding it to the available stacks. |
| popping from an empty stack | If all stacks are empty when popping, the algorithm should return -1. |
| popping from the overall DinnerPlateStacks when no stacks are present | If no stacks have ever been added, or they have all been popped, return -1. |
| Capacity is zero or negative | Throw an IllegalArgumentException or return an error code as an invalid capacity. |
| pushing and popping from stacks that become empty and need to be removed | The algorithm needs to efficiently track the leftmost non-empty and rightmost non-full stacks and update them after pushes and pops. |
| repeated pushing and popping that cause excessive stack creation and deletion | The algorithm should aim for creating new stacks only when needed and reusing or cleaning up the empty stacks to avoid memory leaks. |
| attempting to popAt an invalid index (index out of bounds) | The algorithm should check if the index is within the bounds of the list of stacks and handle the case gracefully, potentially returning -1 or throwing an exception. |
| popAt from an empty stack at a valid index | If the stack at index is empty return -1, indicating no value can be popped. |