Cracking The Coding Interview Together – Problem 3.1: Three in One
Today’s problem looks deceptively simple. At first glance, it feels like something you might solve in a few minutes. But once you begin thinking about scalability, memory management, and trade-offs, you realize this problem quietly tests how well you understand stack fundamentals and data structure design.
Let’s explore it step by step, the same way you would in an actual interview.
As always, we’ll follow the same structure that you would use in a real interview.
- Understand the problem statement together
- Ask any questions, that you would like to ask the interviewer
- I would urge you to take your time here and try to come up with your own solution before going forward
- Think how you would go about solving the problem(you would be talking out loud in front of the actual interviewer)
- Write code and understand how it works and explain it to your interviewer
Problem statement
Three in One:
Describe how you could use a single array to implement three stacks.
Analyse the problem statement together
Before jumping into code, let’s make sure we truly understand what is being asked.
Normally, when we implement stacks, we allocate a separate data structure for each stack. But here, the interviewer is forcing us to think differently. Instead of using three independent stacks, we must use one single array and somehow make it behave like three separate stacks.
In simple terms:
- We need three stacks.
- All stacks must share one array.
- Each stack must support standard stack operations:
pushpoppeekisEmpty
That’s it. Sounds easy, right? Let’s dig deeper.
Questions for the interviewer
This is where most candidates rush. Don’t.
Clarifying requirements often saves you from writing the wrong solution.
Here are the questions I would ask:
1. Should all stacks have equal capacity?
This is important. If yes, the problem becomes simpler. If no, things become significantly more dynamic.
2. Is the total array size fixed?
Knowing whether resizing is allowed changes our design completely.
3. Should stacks grow independently?
For example:
- What if stack 1 is full but stack 2 is almost empty?
4. What should happen when one stack overflows?
Return an error? Resize? Shift elements?
This is where most candidates rush. Don’t.
Clarifying requirements often saves you from writing the wrong solution.
Most interviewers expect you to start with:
- Fixed array size
- Equal partitioning among stacks
- No dynamic resizing initially
Once you solve this, you can discuss optimizations.
Think about the Solution
Take a moment and visualize.
You have:
Array → [ _ _ _ _ _ _ _ _ _ ]
You need to divide this array into three logical stacks.
How would you separate them?
Think about this before reading further.
Think Out Loud: How Would You Approach This?
Let’s reason step by step, just like you would while speaking to an interviewer.
First Idea: Divide the Array into Three Equal Parts
This is the most straightforward approach.
If the array has size n, then each stack gets:
n / 3 elementsExample:
Index: 0 1 2 | 3 4 5 | 6 7 8
Stack: S1 S2 S3Each stack operates only within its assigned section.
What Extra Information Do We Need?
For each stack, we must track:
- Where the stack starts
- Where the current top element is
So we need:
int[] tops = new int[3];
Each index stores the current top for that stack.
Why This Works
- Each stack behaves independently
- No stack overwrites another
- Operations remain O(1)
But…
What Are the Limitations?
This is where interviews get interesting.
Suppose:
- Stack 1 is full
- Stack 2 and Stack 3 are almost empty
Our array still refuses to let Stack 1 grow.
This is wasted space.
Good candidates mention this limitation.
Great candidates propose improvements later.
Write code and explain
Now let’s translate this idea into code.
Java code
class ThreeInOneStack {
private int numberOfStacks = 3;
private int stackCapacity;
private int[] values;
private int[] sizes;
public ThreeInOneStack(int stackSize) {
stackCapacity = stackSize;
values = new int[stackSize * numberOfStacks];
sizes = new int[numberOfStacks];
}
// Push operation
public void push(int stackNum, int value) {
if (isFull(stackNum)) {
throw new StackOverflowError("Stack is full");
}
sizes[stackNum]++;
values[indexOfTop(stackNum)] = value;
}
// Pop operation
public int pop(int stackNum) {
if (isEmpty(stackNum)) {
throw new EmptyStackException();
}
int topIndex = indexOfTop(stackNum);
int value = values[topIndex];
values[topIndex] = 0;
sizes[stackNum]--;
return value;
}
// Peek operation
public int peek(int stackNum) {
if (isEmpty(stackNum)) {
throw new EmptyStackException();
}
return values[indexOfTop(stackNum)];
}
public boolean isEmpty(int stackNum) {
return sizes[stackNum] == 0;
}
public boolean isFull(int stackNum) {
return sizes[stackNum] == stackCapacity;
}
private int indexOfTop(int stackNum) {
int offset = stackNum * stackCapacity;
int size = sizes[stackNum];
return offset + size - 1;
}
}Explain the Code in Plain English
Here is how you would explain this to an interviewer.
Step 1: Partition the Array
We allocate:
array size = stackCapacity × 3
Each stack gets a fixed segment.
Step 2: Track Stack Sizes
sizes[stackNum] tells us how many elements exist in that stack.
Step 3: Calculate Top Index
offset = stackNum × stackCapacitytopIndex = offset + size - 1
This gives us the exact position inside the shared array.
Step 4: Push and Pop Operations
We simply adjust the sizes array and place values accordingly.
Time & Space Complexity
Let’s be explicit — interviewers care about this.
Time Complexity
Push → O(1)
Pop → O(1)
Peek → O(1)Space Complexity
O(n)Follow-Up Discussion (This Is Where You Impress Interviewers)
Now let’s talk about the real-world improvement.
Problem with Equal Partitioning
Memory becomes inefficient when stacks grow unevenly.
Better Approach: Flexible Division
Instead of fixed partitions:
- Allow stacks to expand dynamically
- Shift neighboring stacks when needed
- Maintain metadata about boundaries
This is more complex but more space efficient.
Mentioning this shows strong design thinking.
Final Thoughts
This problem is a great reminder that interviews are not about memorizing tricks. They are about reasoning, communication, and clarity of thought.
If you can explain this solution clearly—especially the intuition behind why resetting the pointer works—you are demonstrating exactly what interviewers are looking for.
Take your time with this one. Draw it out on paper. Walk through the pointers step by step. Try explaining it aloud.
That’s how these concepts truly stick.
I’ll see you in the next one. Until then—happy coding.This problem teaches something subtle but powerful:
Good engineers don’t just write code that works.
They write code that understands constraints, trade-offs, and future scalability.
If you solve the basic version confidently and then discuss improvements naturally, you demonstrate exactly what interviewers look for — clarity, structure, and thoughtful design.
Take your time with this one. Try implementing both fixed and flexible versions if you can.
I’ll see you in the next one. Until then — happy coding.
Member discussion