Cracking The Coding Interview Together – Problem 3.1: Three in One

How do you implement three independent stacks using just one array? In this CTCI deep dive, we break down intuition, walk through a clean Java solution, discuss trade-offs, and explore interview-ready optimizations.
Cracking The Coding Interview Together – Problem 3.1: Three in One
Photo by Levi Meir Clancy / Unsplash

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.

  1. Understand the problem statement together
  2. Ask any questions, that you would like to ask the interviewer
  3. I would urge you to take your time here and try to come up with your own solution before going forward
  4. Think how you would go about solving the problem(you would be talking out loud in front of the actual interviewer)
  5. 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:
    • push
    • pop
    • peek
    • isEmpty

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 elements

Example:

Index:  0 1 2 | 3 4 5 | 6 7 8
Stack:  S1     S2      S3

Each 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 × stackCapacity
topIndex = 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.