Given two integers n and k. Implement k stacks using a single array of size n. Multiple stacks must share the same array space while supporting the following operations:
push(x, i): Push element x into the i-th stack.
pop(i): Pop the top element from the i-th stack and return it.
Table of Content
[Naive Approach] Dividing Array into k Segments
The idea is to divide the array into fixed parts, one for each stack. If the array size is n and there are k stacks, then each stack gets n/k slots.
We maintain another array top[] of size k, where top[i] stores the index of the top element of the i-th stack. Initially, all top[i] are set to the start of their respective segments minus one (indicating empty stacks).
Push is done by incrementing top[i] and inserting the element, while pop is done by returning the element at top[i] and then decrementing it.

Limitation: This approach leads to inefficient space utilization, since one stack may become full even when other stacks still have free space available.
#include <iostream>
#include <vector>
using namespace std;
class kStacks {
// main array to store elements
int *arr;
// stores top index for each stack
int *top;
// size of each segment
int segSize;
public:
kStacks(int n, int k) {
segSize = n / k;
arr = new int[n];
top = new int[k];
// initialize top pointers
for (int i = 0; i < k; i++)
top[i] = i * segSize - 1;
}
// push element x into stack i
void push(int x, int i) {
int end = (i + 1) * segSize - 1;
if (top[i] == end) {
cout << "Stack " << i << " overflow" << endl;
return;
}
top[i]++;
arr[top[i]] = x;
}
// pop element from stack i
int pop(int i) {
int start = i * segSize;
if (top[i] < start) {
cout << "Stack " << i << " underflow" << endl;
return -1;
}
int val = arr[top[i]];
top[i]--;
return val;
}
};
int main() {
int n = 4, k = 2;
kStacks st(n, k);
// Each operations has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation → {2, stackNumber}
vector<vector<int>> operations = {
{1, 5, 0},
{1, 9, 0},
{1, 10, 0},
{1, 15, 1},
{2, 0},
{2, 1},
{2, 1}
};
for (auto &op : operations) {
if (op[0] == 1) {
int x = op[1], m = op[2];
st.push(x, m);
} else if (op[0] == 2) {
int m = op[1];
int res = st.pop(m);
if (res != -1)
cout << "Popped Element: " << res << endl;
}
}
return 0;
}
import java.util.Vector;
class kStacks {
// main array to store elements
private int[] arr;
// stores top index for each stack
private int[] top;
// size of each segment
private int segSize;
public kStacks(int n, int k) {
segSize = n / k;
arr = new int[n];
top = new int[k];
// initialize top pointers
for (int i = 0; i < k; i++)
top[i] = i * segSize - 1;
}
// push element x into stack i
public void push(int x, int i) {
int end = (i + 1) * segSize - 1;
if (top[i] == end) {
System.out.println("Stack " + i + " overflow");
return;
}
top[i]++;
arr[top[i]] = x;
}
// pop element from stack i
public int pop(int i) {
int start = i * segSize;
if (top[i] < start) {
System.out.println("Stack " + i + " underflow");
return -1;
}
int val = arr[top[i]];
top[i]--;
return val;
}
}
public class GfG {
public static void main(String[] args) {
int n = 4, k = 2;
kStacks st = new kStacks(n, k);
// Each operations has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation → {2, stackNumber}
int[][] operations = {
{1, 5, 0},
{1, 9, 0},
{1, 10, 0},
{1, 15, 1},
{2, 0},
{2, 1},
{2, 1}
};
for (int[] op : operations) {
if (op[0] == 1) {
int x = op[1], m = op[2];
st.push(x, m);
} else if (op[0] == 2) {
int m = op[1];
int res = st.pop(m);
if (res != -1)
System.out.println("Popped Element: " + res);
}
}
}
}
class kStacks:
# main array to store elements
def __init__(self, n, k):
self.segSize = n // k
self.arr = [0] * n
self.top = [i * self.segSize - 1 for i in range(k)]
# push element x into stack i
def push(self, x, i):
end = (i + 1) * self.segSize - 1
if self.top[i] == end:
print(f'Stack {i} overflow')
return
self.top[i] += 1
self.arr[self.top[i]] = x
# pop element from stack i
def pop(self, i):
start = i * self.segSize
if self.top[i] < start:
print(f'Stack {i} underflow')
return -1
val = self.arr[self.top[i]]
self.top[i] -= 1
return val
if __name__ == '__main__':
n = 4
k = 2
st = kStacks(n, k)
# Each operation has the following format:
# 1. Push operation → [1, value, stackNumber]
# 2. Pop operation → [2, stackNumber]
operations = [
[1, 5, 0],
[1, 9, 0],
[1, 10, 0],
[1, 15, 1],
[2, 0],
[2, 1],
[2, 1]
]
for op in operations:
if op[0] == 1:
x = op[1]
m = op[2]
st.push(x, m)
elif op[0] == 2:
m = op[1]
res = st.pop(m)
if res != -1:
print(f'Popped Element: {res}')
using System;
class kStacks {
// main array to store elements
private int[] arr;
// stores top index for each stack
private int[] top;
// size of each segment
private int segSize;
public kStacks(int n, int k) {
segSize = n / k;
arr = new int[n];
top = new int[k];
// initialize top pointers
for (int i = 0; i < k; i++)
top[i] = i * segSize - 1;
}
// push element x into stack i
public void push(int x, int i) {
int end = (i + 1) * segSize - 1;
if (top[i] == end) {
Console.WriteLine("Stack " + i + " overflow");
return;
}
top[i]++;
arr[top[i]] = x;
}
// pop element from stack i
public int pop(int i) {
int start = i * segSize;
if (top[i] < start) {
Console.WriteLine("Stack " + i + " underflow");
return -1;
}
int val = arr[top[i]];
top[i]--;
return val;
}
}
class GfG {
static void Main() {
int n = 4, k = 2;
kStacks st = new kStacks(n, k);
// Each operation has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation → {2, stackNumber}
int[][] operations = {
new int[] {1, 5, 0},
new int[] {1, 9, 0},
new int[] {1, 10, 0},
new int[] {1, 15, 1},
new int[] {2, 0},
new int[] {2, 1},
new int[] {2, 1}
};
foreach (var op in operations) {
if (op[0] == 1) {
int x = op[1], m = op[2];
st.push(x, m);
} else if (op[0] == 2) {
int m = op[1];
int res = st.pop(m);
if (res != -1)
Console.WriteLine("Popped Element: " + res);
}
}
}
}
class kStacks {
// main array to store elements
arr;
// stores top index for each stack
top;
// size of each segment
segSize;
constructor(n, k) {
this.segSize = Math.floor(n / k);
this.arr = new Array(n);
this.top = new Array(k);
// initialize top pointers
for (let i = 0; i < k; i++)
this.top[i] = i * this.segSize - 1;
}
// push element x into stack i
push(x, i) {
const end = (i + 1) * this.segSize - 1;
if (this.top[i] === end) {
console.log(`Stack ${i} overflow`);
return;
}
this.top[i]++;
this.arr[this.top[i]] = x;
}
// pop element from stack i
pop(i) {
const start = i * this.segSize;
if (this.top[i] < start) {
console.log(`Stack ${i} underflow`);
return -1;
}
const val = this.arr[this.top[i]];
this.top[i]--;
return val;
}
}
// Driver Code
const n = 4, k = 2;
const st = new kStacks(n, k);
// Each operation has the following format:
// 1. Push operation → [1, value, stackNumber]
// 2. Pop operation → [2, stackNumber]
const operations = [
[1, 5, 0],
[1, 9, 0],
[1, 10, 0],
[1, 15, 1],
[2, 0],
[2, 1],
[2, 1]
];
for (const op of operations) {
if (op[0] === 1) {
const x = op[1], m = op[2];
st.push(x, m);
} else if (op[0] === 2) {
const m = op[1];
const res = st.pop(m);
if (res !== -1)
console.log(`Popped Element: ${res}`);
}
}
Output
Stack 0 overflow Poped Element: 9 Poped Element: 15 Stack 1 underflow
Time Complexity: O(1) for push operation and pop operation
Auxiliary Space: O(n)
[Efficient Approach] Using Space Optimized Method
The idea is to allow all stacks to share the array dynamically instead of dividing it into fixed parts. For this, we use three additional structures:
- An array top[] of size k, where top[i] stores the index of the top element of the i-th stack.
- An array next[] of size n, which links free slots together and also helps connect elements within a stack.
- A variable freeTop that stores the index of the first free slot in the array.
Push Operation:
When we push an element into stack i, we pick the first free slot from freeTop. The element is placed at this index, and the next[] array is updated to link this slot with the previous top of stack i. Finally, top[i] is updated to this new index, and freeTop moves to the next available free slot.
Pop Operation:
When we pop from stack i, we look at the index stored in top[i]. The element at that index is removed, and top[i] is updated to the next link stored in next[]. The freed index is then added back to the free list by updating freeTop.
Illustrations:
#include <iostream>
using namespace std;
class kStacks {
// main array to store elements
int *arr;
// array to store indexes of top elements of stacks
int *top;
// array to store next entry (for free list and stack links)
int *next;
// beginning index of free list
int freeTop;
public:
kStacks(int n, int k) {
arr = new int[n];
top = new int[k];
next = new int[n];
// initialize tops of all stacks as empty
for (int i = 0; i < k; i++)
top[i] = -1;
// initialize free list
freeTop = 0;
for (int i = 0; i < n - 1; i++)
next[i] = i + 1;
next[n - 1] = -1;
}
// push element x into stack i
void push(int x, int i) {
if (freeTop == -1) {
cout << "Stack Overflow\n";
return;
}
// take index from free list
int index = freeTop;
// update free list
freeTop = next[index];
// put element in array
arr[index] = x;
// link new element to previous top
next[index] = top[i];
// update top of stack
top[i] = index;
}
// pop element from stack i
int pop(int i) {
if (top[i] == -1) {
cout << "Stack Underflow\n";
return -1;
}
// get top index
int index = top[i];
// update top to next element
top[i] = next[index];
// add index back to free list
next[index] = freeTop;
freeTop = index;
// return popped element
return arr[index];
}
};
int main() {
int n = 9, k = 3;
kStacks st(n, k);
// Each query has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation → {2, stackNumber}
int operations[][3] = {
{1, 10, 1},
{1, 20, 1},
{1, 30, 1},
{1, 100, 0},
{1, 200, 0},
{2, 1},
{2, 1},
{2, 0},
{1, 2, 2}
};
int op = sizeof(operations) / sizeof(operations[0]);
for (int i = 0; i < op; i++) {
if (operations[i][0] == 1) {
int x = operations[i][1], m = operations[i][2];
st.push(x, m);
} else if (operations[i][0] == 2) {
int m = operations[i][1];
int res = st.pop(m);
if (res != -1)
cout << "Popped Element: " << res << endl;
}
}
return 0;
}
import java.util.Arrays;
class kStacks {
// main array to store elements
private int[] arr;
// array to store indexes of top elements of stacks
private int[] top;
// array to store next entry (for free list and stack links)
private int[] next;
// beginning index of free list
private int freeTop;
public kStacks(int n, int k) {
arr = new int[n];
top = new int[k];
next = new int[n];
// initialize tops of all stacks as empty
Arrays.fill(top, -1);
// initialize free list
freeTop = 0;
for (int i = 0; i < n - 1; i++)
next[i] = i + 1;
next[n - 1] = -1;
}
// push element x into stack i
public void push(int x, int i) {
if (freeTop == -1) {
System.out.println("Stack Overflow");
return;
}
// take index from free list
int index = freeTop;
// update free list
freeTop = next[index];
// put element in array
arr[index] = x;
// link new element to previous top
next[index] = top[i];
// update top of stack
top[i] = index;
}
// pop element from stack i
public int pop(int i) {
if (top[i] == -1) {
System.out.println("Stack Underflow");
return -1;
}
// get top index
int index = top[i];
// update top to next element
top[i] = next[index];
// add index back to free list
next[index] = freeTop;
freeTop = index;
// return popped element
return arr[index];
}
}
public class Main {
public static void main(String[] args) {
int n = 9, k = 3;
kStacks st = new kStacks(n, k);
// Each operation has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation → {2, stackNumber}
int[][] operations = {
{1, 10, 1},
{1, 20, 1},
{1, 30, 1},
{1, 100, 0},
{1, 200, 0},
{2, 1},
{2, 1},
{2, 0},
{1, 2, 2}
};
int op = operations.length;
for (int i = 0; i < op; i++) {
if (operations[i][0] == 1) {
int x = operations[i][1], m = operations[i][2];
st.push(x, m);
} else if (operations[i][0] == 2) {
int m = operations[i][1];
int res = st.pop(m);
if (res != -1)
System.out.println("Popped Element: " + res);
}
}
}
}
class kStacks:
def __init__(self, n, k):
self.arr = [0] * n
self.top = [-1] * k
self.next = [0] * n
self.freeTop = 0
for i in range(n - 1):
self.next[i] = i + 1
self.next[n - 1] = -1
def push(self, x, i):
if self.freeTop == -1:
print("Stack Overflow")
return
index = self.freeTop
self.freeTop = self.next[index]
self.arr[index] = x
self.next[index] = self.top[i]
self.top[i] = index
def pop(self, i):
if self.top[i] == -1:
print("Stack Underflow")
return -1
index = self.top[i]
self.top[i] = self.next[index]
self.next[index] = self.freeTop
self.freeTop = index
return self.arr[index]
if __name__ == '__main__':
n = 9
k = 3
st = kStacks(n, k)
# Each operation has the following format:
# 1. Push operation → (1, value, stackNumber)
# 2. Pop operation → (2, stackNumber)
operations = [
(1, 10, 1),
(1, 20, 1),
(1, 30, 1),
(1, 100, 0),
(1, 200, 0),
(2, 1),
(2, 1),
(2, 0),
(1, 2, 2)
]
for op in operations:
if op[0] == 1:
x, m = op[1], op[2]
st.push(x, m)
elif op[0] == 2:
m = op[1]
res = st.pop(m)
if res != -1:
print(f'Popped Element: {res}')
using System;
public class kStacks {
// main array to store elements
private int[] arr;
// array to store indexes of top elements of stacks
private int[] top;
// array to store next entry (for free list and stack links)
private int[] next;
// beginning index of free list
private int freeTop;
public kStacks(int n, int k) {
arr = new int[n];
top = new int[k];
next = new int[n];
// initialize tops of all stacks as empty
for (int i = 0; i < k; i++)
top[i] = -1;
// initialize free list
freeTop = 0;
for (int i = 0; i < n - 1; i++)
next[i] = i + 1;
next[n - 1] = -1;
}
// push element x into stack i
public void push(int x, int i) {
if (freeTop == -1) {
Console.WriteLine("Stack Overflow");
return;
}
// take index from free list
int index = freeTop;
// update free list
freeTop = next[index];
// put element in array
arr[index] = x;
// link new element to previous top
next[index] = top[i];
// update top of stack
top[i] = index;
}
// pop element from stack i
public int pop(int i) {
if (top[i] == -1) {
Console.WriteLine("Stack Underflow");
return -1;
}
// get top index
int index = top[i];
// update top to next element
top[i] = next[index];
// add index back to free list
next[index] = freeTop;
freeTop = index;
// return popped element
return arr[index];
}
}
public class GfG {
public static void Main(string[] args) {
int n = 9, k = 3;
kStacks st = new kStacks(n, k);
// Each operation has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation → {2, stackNumber}
int[][] operations = {
new int[] {1, 10, 1},
new int[] {1, 20, 1},
new int[] {1, 30, 1},
new int[] {1, 100, 0},
new int[] {1, 200, 0},
new int[] {2, 1},
new int[] {2, 1},
new int[] {2, 0},
new int[] {1, 2, 2}
};
int opCount = operations.Length;
for (int i = 0; i < opCount; i++) {
if (operations[i][0] == 1) {
int x = operations[i][1], m = operations[i][2];
st.push(x, m);
}
else if (operations[i][0] == 2) {
int m = operations[i][1];
int res = st.pop(m);
if (res != -1)
Console.WriteLine("Popped Element: " + res);
}
}
}
}
class kStacks {
// main array to store elements
arr;
// array to store indexes of top elements of stacks
top;
// array to store next entry (for free list and stack links)
next;
// beginning index of free list
freeTop;
constructor(n, k) {
this.arr = new Array(n);
this.top = new Array(k);
this.next = new Array(n);
// initialize tops of all stacks as empty
for (let i = 0; i < k; i++)
this.top[i] = -1;
// initialize free list
this.freeTop = 0;
for (let i = 0; i < n - 1; i++)
this.next[i] = i + 1;
this.next[n - 1] = -1;
}
// push element x into stack i
push(x, i) {
if (this.freeTop === -1) {
console.log('Stack Overflow');
return;
}
// take index from free list
let index = this.freeTop;
// update free list
this.freeTop = this.next[index];
// put element in array
this.arr[index] = x;
// link new element to previous top
this.next[index] = this.top[i];
// update top of stack
this.top[i] = index;
}
// pop element from stack i
pop(i) {
if (this.top[i] === -1) {
console.log('Stack Underflow');
return -1;
}
// get top index
let index = this.top[i];
// update top to next element
this.top[i] = this.next[index];
// add index back to free list
this.next[index] = this.freeTop;
this.freeTop = index;
// return popped element
return this.arr[index];
}
}
// Driver Code
let n = 9, k = 3;
let st = new kStacks(n, k);
// Each operation has the following format:
// 1. Push operation → [1, value, stackNumber]
// 2. Pop operation → [2, stackNumber]
let operations = [
[1, 10, 1],
[1, 20, 1],
[1, 30, 1],
[1, 100, 0],
[1, 200, 0],
[2, 1],
[2, 1],
[2, 0],
[1, 2, 2]
];
let opCount = operations.length;
for (let i = 0; i < opCount; i++) {
if (operations[i][0] === 1) {
let x = operations[i][1], m = operations[i][2];
st.push(x, m);
} else if (operations[i][0] === 2) {
let m = operations[i][1];
let res = st.pop(m);
if (res !== -1)
console.log('Popped Element: ' + res);
}
}
Output
Popped Element: 30 Popped Element: 20 Popped Element: 200
Time Complexity: O(1) for push operation and pop operation
Auxiliary Space: O(n)
Related Article: