Changing this from recursion to iteration - algorithm

Some pseudocode:
func F(int x. int y, array p){
p[x] = 1;
if (x<=y){
for each item in getItems(x,p){
p = F(item,y,p);
}
}
return p;
}
getItems() returns an array of numbers based on x and p, and isn't important for the sake of this question, but it returns a few numbers that are above and below x. However this means if x is too big then I blow up recursion stack since it'll dig down deep below x.
How can I change this to iteration?

You can do it by emulating the call stack:
struct stackentry {
int x;
Item item; // see exercise for reader, below
};
func F(int x, int y, array p){
dynamic_list_of_stackentry mystack;
start:
p[x] = 1;
if (x<=y){
for each item in getItems(x,p){
mystack.push(stackentry(x, item));
x = item
goto start
resume:
x = mystack.top().x;
item = mystack.top().item;
mystack.pop();
}
}
if mystack.size() > 0:
goto resume
return p;
}
Left as an exercise: change the iteration so that you can store, as part of the stack entry, the collection that you're currently iterating over (from getItems()) and your current position in it.
I'm not claiming this is elegant code, but you can refactor from this starting point of a non-recursive function that does the same as your recursive one. For example your next step might be:
func F(int x, int y, array p){
dynamic_list_of_int mystack;
mystack.push(x)
while not mystack.empty() {
x = mystack.top();
mystack.pop();
p[x] = 1;
if (x <= y) {
for each item in reversed(getItems(x,p)) {
mystack.push(item);
}
}
}
return p;
}

You might be able to keep the recursive version (without the stack overflow) by adding a guard that prevents you from double-processing x values
func F(int x. int y, array p){
if(p[x] != 1) {
p[x] = 1;
if (x<=y){
for each item in getItems(x,p){
p = F(item,y,p);
}
}
}
return p;
}
If some of your array values might have been initialized to 1, then change this to something like
if(p[x] != null) {
p[x] = null;
i.e. assign a value that you know isn't used in the initial array. Then when the function completes its processing, iterate through the array and set all null values to 1.

Related

Paper cut algorithm

I want to create a function to determine the most number of pieces of paper on a parent paper size
The formula above is still not optimal. If using the above formula will only produce at most 32 cut/sheet.
I want it like below.
This seems to be a very difficult problem to solve optimally. See http://lagrange.ime.usp.br/~lobato/packing/ for a discussion of a 2008 paper claiming that the problem is believed (but not proven) to be NP-hard. The researchers found some approximation algorithms and implemented them on that website.
The following solution uses Top-Down Dynamic Programming to find optimal solutions to this problem. I am providing this solution in C#, which shouldn't be too hard to convert into the language of your choice (or whatever style of pseudocode you prefer). I have tested this solution on your specific example and it completes in less than a second (I'm not sure how much less than a second).
It should be noted that this solution assumes that only guillotine cuts are allowed. This is a common restriction for real-world 2D Stock-Cutting applications and it greatly simplifies the solution complexity. However, CS, Math and other programming problems often allow all types of cutting, so in that case this solution would not necessarily find the optimal solution (but it would still provide a better heuristic answer than your current formula).
First, we need a value-structure to represent the size of the starting stock, the desired rectangle(s) and of the pieces cut from the stock (this needs to be a value-type because it will be used as the key to our memoization cache and other collections, and we need to to compare the actual values rather than an object reference address):
public struct Vector2D
{
public int X;
public int Y;
public Vector2D(int x, int y)
{
X = x;
Y = y;
}
}
Here is the main method to be called. Note that all values need to be in integers, for the specific case above this just means multiplying everything by 100. These methods here require integers, but are otherwise are scale-invariant so multiplying by 100 or 1000 or whatever won't affect performance (just make sure that the values don't overflow an int).
public int SolveMaxCount1R(Vector2D Parent, Vector2D Item)
{
// make a list to hold both the item size and its rotation
List<Vector2D> itemSizes = new List<Vector2D>();
itemSizes.Add(Item);
if (Item.X != Item.Y)
{
itemSizes.Add(new Vector2D(Item.Y, Item.X));
}
int solution = SolveGeneralMaxCount(Parent, itemSizes.ToArray());
return solution;
}
Here is an example of how you would call this method with your parameter values. In this case I have assumed that all of the solution methods are part of a class called SolverClass:
SolverClass solver = new SolverClass();
int count = solver.SolveMaxCount1R(new Vector2D(2500, 3800), new Vector2D(425, 550));
//(all units are in tenths of a millimeter to make everything integers)
The main method calls a general solver method for this type of problem (that is not restricted to just one size rectangle and its rotation):
public int SolveGeneralMaxCount(Vector2D Parent, Vector2D[] ItemSizes)
{
// determine the maximum x and y scaling factors using GCDs (Greastest
// Common Divisor)
List<int> xValues = new List<int>();
List<int> yValues = new List<int>();
foreach (Vector2D size in ItemSizes)
{
xValues.Add(size.X);
yValues.Add(size.Y);
}
xValues.Add(Parent.X);
yValues.Add(Parent.Y);
int xScale = NaturalNumbers.GCD(xValues);
int yScale = NaturalNumbers.GCD(yValues);
// rescale our parameters
Vector2D parent = new Vector2D(Parent.X / xScale, Parent.Y / yScale);
var baseShapes = new Dictionary<Vector2D, Vector2D>();
foreach (var size in ItemSizes)
{
var reducedSize = new Vector2D(size.X / xScale, size.Y / yScale);
baseShapes.Add(reducedSize, reducedSize);
}
//determine the minimum values that an allowed item shape can fit into
_xMin = int.MaxValue;
_yMin = int.MaxValue;
foreach (var size in baseShapes.Keys)
{
if (size.X < _xMin) _xMin = size.X;
if (size.Y < _yMin) _yMin = size.Y;
}
// create the memoization cache for shapes
Dictionary<Vector2D, SizeCount> shapesCache = new Dictionary<Vector2D, SizeCount>();
// find the solution pattern with the most finished items
int best = solveGMC(shapesCache, baseShapes, parent);
return best;
}
private int _xMin;
private int _yMin;
The general solution method calls a recursive worker method that does most of the actual work.
private int solveGMC(
Dictionary<Vector2D, SizeCount> shapeCache,
Dictionary<Vector2D, Vector2D> baseShapes,
Vector2D sheet )
{
// have we already solved this size?
if (shapeCache.ContainsKey(sheet)) return shapeCache[sheet].ItemCount;
SizeCount item = new SizeCount(sheet, 0);
if ((sheet.X < _xMin) || (sheet.Y < _yMin))
{
// if it's too small in either dimension then this is a scrap piece
item.ItemCount = 0;
}
else // try every way of cutting this sheet (guillotine cuts only)
{
int child0;
int child1;
// try every size of horizontal guillotine cut
for (int c = sheet.X / 2; c > 0; c--)
{
child0 = solveGMC(shapeCache, baseShapes, new Vector2D(c, sheet.Y));
child1 = solveGMC(shapeCache, baseShapes, new Vector2D(sheet.X - c, sheet.Y));
if (child0 + child1 > item.ItemCount)
{
item.ItemCount = child0 + child1;
}
}
// try every size of vertical guillotine cut
for (int c = sheet.Y / 2; c > 0; c--)
{
child0 = solveGMC(shapeCache, baseShapes, new Vector2D(sheet.X, c));
child1 = solveGMC(shapeCache, baseShapes, new Vector2D(sheet.X, sheet.Y - c));
if (child0 + child1 > item.ItemCount)
{
item.ItemCount = child0 + child1;
}
}
// if no children returned finished items, then the sheet is
// either scrap or a finished item itself
if (item.ItemCount == 0)
{
if (baseShapes.ContainsKey(item.Size))
{
item.ItemCount = 1;
}
else
{
item.ItemCount = 0;
}
}
}
// add the item to the cache before we return it
shapeCache.Add(item.Size, item);
return item.ItemCount;
}
Finally, the general solution method uses a GCD function to rescale the dimensions to achieve scale-invariance. This is implemented in a static class called NaturalNumbers. I have included the rlevant parts of this class below:
static class NaturalNumbers
{
/// <summary>
/// Returns the Greatest Common Divisor of two natural numbers.
/// Returns Zero if either number is Zero,
/// Returns One if either number is One and both numbers are >Zero
/// </summary>
public static int GCD(int a, int b)
{
if ((a == 0) || (b == 0)) return 0;
if (a >= b)
return gcd_(a, b);
else
return gcd_(b, a);
}
/// <summary>
/// Returns the Greatest Common Divisor of a list of natural numbers.
/// (Note: will run fastest if the list is in ascending order)
/// </summary>
public static int GCD(IEnumerable<int> numbers)
{
// parameter checks
if (numbers == null || numbers.Count() == 0) return 0;
int first = numbers.First();
if (first <= 1) return 0;
int g = (int)first;
if (g <= 1) return g;
int i = 0;
foreach (int n in numbers)
{
if (i == 0)
g = n;
else
g = GCD(n, g);
if (g <= 1) return g;
i++;
}
return g;
}
// Euclidian method with Euclidian Division,
// From: https://en.wikipedia.org/wiki/Euclidean_algorithm
private static int gcd_(int a, int b)
{
while (b != 0)
{
int t = b;
b = (a % b);
a = t;
}
return a;
}
}
Please let me know of any problems or questions you might have with this solution.
Oops, forgot that I was also using this class:
public class SizeCount
{
public Vector2D Size;
public int ItemCount;
public SizeCount(Vector2D itemSize, int itemCount)
{
Size = itemSize;
ItemCount = itemCount;
}
}
As I mentioned in the comments, it would actually be pretty easy to factor this class out of the code, but it's still in there right now.

Partition sort for doubly linked list

Code translated to C from Wirth's book is following
void quicksort(int *array, int left, int right)
{
int v=array[(left+right)/2];
int i,j,x;
i=left;
j=right;
do {
while (array[i]<v) i++;
while (array[j]>v) j--;
if (i<=j) {
x=array[i];
array[i]=array[j];
array[j]=x;
i++;
j--;
}
} while (i<=j);
if (j>left) quicksort(array, left, j);
if (i<right) quicksort(array, i, right);
}
but that uses arrays - my stab at doubly linked lists (node structure here ):
void partitonSort(node **head,node **tail)
{
node *v; // here I want to use first or last element as pivot
node *i,*j;
do
{
while(i->key < v->key) i = i->next;
while(j->key > v->key) j = j->prev;
if(/*what boolean expression should I use here*/)
{
/*Is it necessary to replace swap operation
with insert and delete operations and
how to do it */
i = i->next;
j = j->prev;
}
}
while(/*what boolean expression should I use here*/);
if(/*what boolean expression should I use here*/)
partitonSort(head,&j);
if(/*what boolean expression should I use here*/)
partitonSort(&i,tail);
}
I left questions in the code comments:
- Should I replace swap operation with insert and delete
 and how to do this
- What boolean expressions I should use
Here is my concise solution with detailed comments:
/* a node of the doubly linked list */
struct Node
{
int data;
struct Node *next;
struct Node *prev;
};
/* A utility function to swap two elements */
void swap ( int* a, int* b )
{ int t = *a; *a = *b; *b = t; }
// A utility function to find last node of linked list
struct Node *lastNode(Node *root)
{
while (root && root->next)
root = root->next;
return root;
}
/* Considers last element as pivot, places the pivot element at its
correct position in sorted array, and places all smaller (smaller than
pivot) to left of pivot and all greater elements to right of pivot */
Node* partition(Node *l, Node *h)
{
// set pivot as h element
int x = h->data;
// similar to i = l-1 for array implementation
Node *i = l->prev;
// Similar to "for (int j = l; j <= h- 1; j++)"
for (Node *j = l; j != h; j = j->next)
{
if (j->data <= x)
{
// Similar to i++ for array
i = (i == NULL)? l : i->next;
swap(&(i->data), &(j->data));
}
}
i = (i == NULL)? l : i->next; // Similar to i++
swap(&(i->data), &(h->data));
return i;
}
/* A recursive implementation of quicksort for linked list */
void _quickSort(struct Node* l, struct Node *h)
{
if (h != NULL && l != h && l != h->next)
{
struct Node *p = partition(l, h);
_quickSort(l, p->prev);
_quickSort(p->next, h);
}
}
// The main function to sort a linked list. It mainly calls _quickSort()
void quickSort(struct Node *head)
{
// Find last node
struct Node *h = lastNode(head);
// Call the recursive QuickSort
_quickSort(head, h);
}
Yes but I prefer to change links instead of data
Here is pseudocode
PartitionSort(L)
if head[L] != tail[L] then
//Choose the pivot node, first node or last node is the option
pivot := tail[L]
//Partition step, we distribute nodes of the linked list into three sublists
curr := head
while curr != NULL do
if key[curr] < key[pivot] then
pushBack(curr,Less)
else if key[curr] = key[pivot] then
pushBack(curr,Equal)
else
pushBack(curr,Greater)
end if
end if
curr := next[curr]
end while
// Here me make sure that we partitioned linked list correctly
// We should set next of tail pointers and prev of head pointers to NULL
//Now we do recursive calls on sublists with keys not equal to the pivot key
PartitionSort(Less)
PartitionSort(Greater)
// Now we concatenate sublists
if tail[Less] != NULL then
next[tail[Less]] := head[Equal]
else
head[Less] := head[Equal]
end if
if head[Equal] then
prev[head[Equal]] = tail[Less]
tail[Less] = tail[Equal]
end if
if tail[Less] != NULL then
next[tail[Less]] := head[Greater]
else
head[Less] := head[Greater]
end if
if head[Greater] then
prev[head[Greater]] = tail[Less]
tail[Less] = tail[Greater]
end if
L := Less
end if

Make unique array with minimal sum

It is a interview question. Given an array, e.g., [3,2,1,2,7], we want to make all elements in this array unique by incrementing duplicate elements and we require the sum of the refined array is minimal. For example the answer for [3,2,1,2,7] is [3,2,1,4,7] and its sum is 17. Any ideas?
It's not quite as simple as my earlier comment suggested, but it's not terrifically complicated.
First, sort the input array. If it matters to be able to recover the original order of the elements then record the permutation used for the sort.
Second, scan the sorted array from left to right (ie from low to high). If an element is less than or equal to the element to its left, set it to be one greater than that element.
Pseudocode
sar = sort(input_array)
for index = 2:size(sar) ! I count from 1
if sar(index)<=sar(index-1) sar(index) = sar(index-1)+1
forend
Is the sum of the result minimal ? I've convinced myself that it is through some head-scratching and trials but I haven't got a formal proof.
If you only need to find ONE of the best solution, here's the algorythm with some explainations.
The idea of this problem is to find an optimal solution, which can be found only by testing all existing solutions (well, they're infinite, let's stick with the reasonable ones).
I wrote a program in C, because I'm familiar with it, but you can port it to any language you want.
The program does this: it tries to increment one value to the max possible (I'll explain how to find it in the comments under the code sections), than if the solution is not found, decreases this value and goes on with the next one and so on.
It's an exponential algorythm, so it will be very slow on large values of duplicated data (yet, it assures you the best solution is found).
I tested this code with your example, and it worked; not sure if there's any bug left, but the code (in C) is this.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef int BOOL; //just to ease meanings of values
#define TRUE 1
#define FALSE 0
Just to ease comprehension, I did some typedefs. Don't worry.
typedef struct duplicate { //used to fasten the algorythm; it uses some more memory just to assure it's ok
int value;
BOOL duplicate;
} duplicate_t;
int maxInArrayExcept(int *array, int arraySize, int index); //find the max value in array except the value at the index given
//the result is the max value in the array, not counting th index
int *findDuplicateSum(int *array, int arraySize);
BOOL findDuplicateSum_R(duplicate_t *array, int arraySize, int *tempSolution, int *solution, int *totalSum, int currentSum); //resursive function used to find solution
BOOL check(int *array, int arraySize); //checks if there's any repeated value in the solution
These are all the functions we'll need. All split up for comprehension purpose.
First, we have a struct. This struct is used to avoid checking, for every iteration, if the value on a given index was originally duplicated. We don't want to modify any value not duplicated originally.
Then, we have a couple functions: first, we need to see the worst case scenario: every value after the duplicated ones is already occupied: then we need to increment the duplicated value up to the maximum value reached + 1.
Then, there are the main Function we'll discute later about.
The check Function only checks if there's any duplicated value in a temporary solution.
int main() { //testing purpose
int i;
int testArray[] = { 3,2,1,2,7 }; //test array
int nTestArraySize = 5; //test array size
int *solutionArray; //needed if you want to use the solution later
solutionArray = findDuplicateSum(testArray, nTestArraySize);
for (i = 0; i < nTestArraySize; ++i) {
printf("%d ", solutionArray[i]);
}
return 0;
}
This is the main Function: I used it to test everything.
int * findDuplicateSum(int * array, int arraySize)
{
int *solution = malloc(sizeof(int) * arraySize);
int *tempSolution = malloc(sizeof(int) * arraySize);
duplicate_t *duplicate = calloc(arraySize, sizeof(duplicate_t));
int i, j, currentSum = 0, totalSum = INT_MAX;
for (i = 0; i < arraySize; ++i) {
tempSolution[i] = solution[i] = duplicate[i].value = array[i];
currentSum += array[i];
for (j = 0; j < i; ++j) { //to find ALL the best solutions, we should also put the first found value as true; it's just a line more
//yet, it saves the algorythm half of the duplicated numbers (best/this case scenario)
if (array[j] == duplicate[i].value) {
duplicate[i].duplicate = TRUE;
}
}
}
if (findDuplicateSum_R(duplicate, arraySize, tempSolution, solution, &totalSum, currentSum));
else {
printf("No solution found\n");
}
free(tempSolution);
free(duplicate);
return solution;
}
This Function does a lot of things: first, it sets up the solution array, then it initializes both the solution values and the duplicate array, that is the one used to check for duplicated values at startup. Then, we find the current sum and we set the maximum available sum to the maximum integer possible.
Then, the recursive Function is called; this one gives us the info about having found the solution (that should be Always), then we return the solution as an array.
int findDuplicateSum_R(duplicate_t * array, int arraySize, int * tempSolution, int * solution, int * totalSum, int currentSum)
{
int i;
if (check(tempSolution, arraySize)) {
if (currentSum < *totalSum) { //optimal solution checking
for (i = 0; i < arraySize; ++i) {
solution[i] = tempSolution[i];
}
*totalSum = currentSum;
}
return TRUE; //just to ensure a solution is found
}
for (i = 0; i < arraySize; ++i) {
if (array[i].duplicate == TRUE) {
if (array[i].duplicate <= maxInArrayExcept(solution, arraySize, i)) { //worst case scenario, you need it to stop the recursion on that value
tempSolution[i]++;
return findDuplicateSum_R(array, arraySize, tempSolution, solution, totalSum, currentSum + 1);
tempSolution[i]--; //backtracking
}
}
}
return FALSE; //just in case the solution is not found, but we won't need it
}
This is the recursive Function. It first checks if the solution is ok and if it is the best one found until now. Then, if everything is correct, it updates the actual solution with the temporary values, and updates the optimal condition.
Then, we iterate on every repeated value (the if excludes other indexes) and we progress in the recursion until (if unlucky) we reach the worst case scenario: the check condition not satisfied above the maximum value.
Then we have to backtrack and continue with the iteration, that will go on with other values.
PS: an optimization is possible here, if we move the optimal condition from the check into the for: if the solution is already not optimal, we can't expect to find a better one just adding things.
The hard code has ended, and there are the supporting functions:
int maxInArrayExcept(int *array, int arraySize, int index) {
int i, max = 0;
for (i = 0; i < arraySize; ++i) {
if (i != index) {
if (array[i] > max) {
max = array[i];
}
}
}
return max;
}
BOOL check(int *array, int arraySize) {
int i, j;
for (i = 0; i < arraySize; ++i) {
for (j = 0; j < i; ++j) {
if (array[i] == array[j]) return FALSE;
}
}
return TRUE;
}
I hope this was useful.
Write if anything is unclear.
Well, I got the same question in one of my interviews.
Not sure if you still need it. But here's how I did it. And it worked well.
num_list1 = [2,8,3,6,3,5,3,5,9,4]
def UniqueMinSumArray(num_list):
max=min(num_list)
for i,V in enumerate(num_list):
while (num_list.count(num_list[i])>1):
if (max > num_list[i]+1) :
num_list[i] = max + 1
else:
num_list[i]+=1
max = num_list[i]
i+=1
return num_list
print (sum(UniqueMinSumArray(num_list1)))
You can try with your list of numbers and I am sure it will give you the correct unique minimum sum.
I got the same interview question too. But my answer is in JS in case anyone is interested.
For sure it can be improved to get rid of for loop.
function getMinimumUniqueSum(arr) {
// [1,1,2] => [1,2,3] = 6
// [1,2,2,3,3] = [1,2,3,4,5] = 15
if (arr.length > 1) {
var sortedArr = [...arr].sort((a, b) => a - b);
var current = sortedArr[0];
var res = [current];
for (var i = 1; i + 1 <= arr.length; i++) {
// check current equals to the rest array starting from index 1.
if (sortedArr[i] > current) {
res.push(sortedArr[i]);
current = sortedArr[i];
} else if (sortedArr[i] == current) {
current = sortedArr[i] + 1;
// sortedArr[i]++;
res.push(current);
} else {
current++;
res.push(current);
}
}
return res.reduce((a,b) => a + b, 0);
} else {
return 0;
}
}

Issue in making a String Algorithm

Given a string made up of 'a' and 'b' only,the operation that is allowed is to remove a substring of "abb" if present from the string. My question is after applying this operation any no of times can i make the string empty. I need a O(n) algorithm.
Example ,
abbabb-->yes
aabbbb->yes since aabbbb->abb->empty
aaabbb->no since aaabbb->aab
All that i can think upto now is an O(n^2) algorithm in which i sucessively find the position of the substring using substr() or find() and then remove it until string not empty or not found a "abb" in it.
Here is an example of what I suggested in the comment:
for i = 0 to word.length-1
if word[i] == 'b'
if stack.empty() //no corresponding a
return false
if stack.top() == 'a' //first b after an a
stack.push('b')
else //second b after an a
stack.pop() //pop last two letters
stack.pop()
else
stack.push('a')
return stack.empty()
There might be some boundary conditions that needs to be checked, and of course at any point pop() fails you need to return false. Seems to be working for the possible inputs that occurs to me.
The point that needs to be mathematically proved, I think, is the part where I commented "second b after an a". With the assumption that stack was empty at the beginning, if I did not miss anything that point looks correct.
It is not necessary to store anything but the count of unused pairs of b's at the end of the string, as you read it Right to Left. (And it's solved reading input only once, so O(n) time O(1) space) This is very reminiscent of finding a discrete finite automata for a regular language. If you see two b's, increase count. If you see a single b, add half a pair (update a boolean variable and possibly increment count). If you see an a and have no pair of b's, fail, else count--. If you reach the end of the string and there were no extra b's, the string was valid.
Make use of two counters to avoid using stack. Here is the c++ implementaion hope it works.
bool canBeDone(string s)
{
int aCount = 0;
int bCount = 0;
for(int i=0;i<s.length();++i)
{
if(s[i] == 'a')
{
aCount++;
continue;
}
if(s[i] == 'b' && aCount == 0)
return false;
else
{
bCount += 1;
if(bCount == 2)
{
bCount = 0;
aCount--;
}
}
}
if(!aCount && !bCount)return true;
return false;
}
Very simple and straightforward implementation in Erlang O(n) space and time (unfortunately even clwhisk's algorithm needs O(n) space in Erlang because of lists:reverse/1):
-module(abb).
-export([check/1, clwhisk/1, test/0]).
check(L) when is_list(L) ->
check(L, []).
check(L, "bba" ++ T) -> check(L, T);
check([H|T], S) -> check(T, [H|S]);
check([], S) -> S =:= [].
clwhisk(L) when is_list(L) ->
clwhisk(lists:reverse(L), 0).
clwhisk([$b|T], C) -> clwhisk(T, C+1);
clwhisk([$a|T], C) -> C >= 2 andalso clwhisk(T, C-2);
clwhisk(L, C) -> L =:= [] andalso C =:= 0.
test() ->
true = abb:check("abbabb"),
true = abb:check("aabbbb"),
false = abb:check("aaabbb"),
true = abb:check("ababbb"),
true = abb:clwhisk("abbabb"),
true = abb:clwhisk("aabbbb"),
false = abb:clwhisk("aaabbb"),
true = abb:clwhisk("ababbb"),
ok.
And there is C implementation of clwhisk's algorithm as filter:
#include <stdlib.h>
#include <stdio.h>
static inline const char *last(const char* s){
for(;*s && *s!='\n';s++);
return s-1;
}
static int check(const char* s){
int count=0;
const char *ptr = last(s);
for(; ptr >= s; ptr--)
if(*ptr == 'b') {
count++;
}
else if(*ptr == 'a') {
count -= 2;
if(count < 0)
return 0;
}
else return 0;
return count == 0;
}
int main(void) {
char *line = NULL;
size_t len = 0;
while( getline(&line, &len, stdin) != -1 )
if(*line && *line != '\n' && check(line))
fputs(line, stdout);
return EXIT_SUCCESS;
}

How to implement 3 stacks with one array?

Sometimes, I come across the following interview question: How to implement 3 stacks with one array ? Of course, any static allocation is not a solution.
Space (not time) efficient. You could:
1) Define two stacks beginning at the array endpoints and growing in opposite directions.
2) Define the third stack as starting in the middle and growing in any direction you want.
3) Redefine the Push op, so that when the operation is going to overwrite other stack, you shift the whole middle stack in the opposite direction before Pushing.
You need to store the stack top for the first two stacks, and the beginning and end of the third stack in some structure.
Edit
Above you may see an example. The shifting is done with an equal space partitioning policy, although other strategies could be chosen depending upon your problem heuristics.
Edit
Following #ruslik's suggestion, the middle stack could be implemented using an alternating sequence for subsequent pushes. The resulting stack structure will be something like:
| Elem 6 | Elem 4 | Elem 2 | Elem 0 | Elem 1 | Elem 3 | Elem 5 |
In this case, you'll need to store the number n of elements on the middle stack and use the function:
f[n_] := 1/4 ( (-1)^n (-1 + 2 n) + 1) + BS3
to know the next array element to use for this stack.
Although probably this will lead to less shifting, the implementation is not homogeneous for the three stacks, and inhomogeneity (you know) leads to special cases, more bugs and difficulties to maintain code.
As long as you try to arrange all items from one stack together at one "end" of the array, you're lacking space for the third stack.
However, you could "intersperse" the stack elements. Elements of the first stack are at indices i * 3, elements of the second stack are at indices i * 3 + 1, elements of the third stack are at indices i * 3 + 2 (where i is an integer).
+----+----+----+----+----+----+----+----+----+----+----+----+----+..
| A1 : B1 : C1 | A2 : B2 : C2 | : B3 | C3 | : B4 : | :
+----+----+----+----+----+----+----+----+----+----+----+----+----+..
^ ^ ^
A´s top C´s top B´s top
Of course, this scheme is going to waste space, especially when the stacks have unequal sizes. You could create arbitrarily complex schemes similar to the one described above, but without knowing any more constraints for the posed question, I'll stop here.
Update:
Due to the comments below, which do have a very good point, it should be added that interspersing is not necessary, and may even degrade performance when compared to a much simpler memory layout such as the following:
+----+----+----+----+----+----+----+----+----+----+----+----+----+..
| A1 : A2 : : : | B1 : B2 : B3 : B4 : | C1 : C2 : C3 :
+----+----+----+----+----+----+----+----+----+----+----+----+----+..
^ ^ ^
A´s top B´s top C´s top
i.e. giving each stack it's own contiguous block of memory. If the real question is indeed to how to make the best possible use of a fixed amount of memory, in order to not limit each stack more than necessary, then my answer isn't going to be very helpful.
In that case, I'd go with #belisarius' answer: One stack goes to the "bottom" end of the memory area, growing "upwards"; another stack goes to the "top" end of the memory area, growing "downwards", and one stack is in the middle that grows in any direction but is able to move when it gets too close to one of the other stacks.
Maintain a single arena for all three stacks. Each element pushed onto the stack has a backwards pointer to its previous element. The bottom of each stack has a pointer to NULL/None.
The arena maintains a pointer to the next item in the free space. A push adds this element to the respective stack and marks it as no longer in the free space. A pop removes the element from the respective stack and adds it to the free list.
From this sketch, elements in stacks need a reverse pointer and space for the data. Elements in the free space need two pointers, so the free space is implemented as a doubly linked list.
The object containing the three stacks needs a pointer to the top of each stack plus a pointer to the head of the free list.
This data structure uses all the space and pushes and pops in constant time. There is overhead of a single pointer for all data elements in a stack and the free list elements use the maximum of (two pointers, one pointer + one element).
Later: python code goes something like this. Note use of integer indexes as pointers.
class StackContainer(object):
def __init__(self, stack_count=3, size=256):
self.stack_count = stack_count
self.stack_top = [None] * stack_count
self.size = size
# Create arena of doubly linked list
self.arena = [{'prev': x-1, 'next': x+1} for x in range(self.size)]
self.arena[0]['prev'] = None
self.arena[self.size-1]['next'] = None
self.arena_head = 0
def _allocate(self):
new_pos = self.arena_head
free = self.arena[new_pos]
next = free['next']
if next:
self.arena[next]['prev'] = None
self.arena_head = next
else:
self.arena_head = None
return new_pos
def _dump(self, stack_num):
assert 0 <= stack_num < self.stack_count
curr = self.stack_top[stack_num]
while curr is not None:
d = self.arena[curr]
print '\t', curr, d
curr = d['prev']
def _dump_all(self):
print '-' * 30
for i in range(self.stack_count):
print "Stack %d" % i
self._dump(i)
def _dump_arena(self):
print "Dump arena"
curr = self.arena_head
while curr is not None:
d = self.arena[curr]
print '\t', d
curr = d['next']
def push(self, stack_num, value):
assert 0 <= stack_num < self.stack_count
# Find space in arena for new value, update pointers
new_pos = self._allocate()
# Put value-to-push into a stack element
d = {'value': value, 'prev': self.stack_top[stack_num], 'pos': new_pos}
self.arena[new_pos] = d
self.stack_top[stack_num] = new_pos
def pop(self, stack_num):
assert 0 <= stack_num < self.stack_count
top = self.stack_top[stack_num]
d = self.arena[top]
assert d['pos'] == top
self.stack_top[stack_num] = d['prev']
arena_elem = {'prev': None, 'next': self.arena_head}
# Link the current head to the new head
head = self.arena[self.arena_head]
head['prev'] = top
# Set the curr_pos to be the new head
self.arena[top] = arena_elem
self.arena_head = top
return d['value']
if __name__ == '__main__':
sc = StackContainer(3, 10)
sc._dump_arena()
sc.push(0, 'First')
sc._dump_all()
sc.push(0, 'Second')
sc.push(0, 'Third')
sc._dump_all()
sc.push(1, 'Fourth')
sc._dump_all()
print sc.pop(0)
sc._dump_all()
print sc.pop(1)
sc._dump_all()
I have a solution for this question. The following program makes the best use of the array (in my case, an array of StackNode Objects). Let me know if you guys have any questions about this. [It's pretty late out here, so i didn't bother to document the code - I know, I should :) ]
public class StackNode {
int value;
int prev;
StackNode(int value, int prev) {
this.value = value;
this.prev = prev;
}
}
public class StackMFromArray {
private StackNode[] stackNodes = null;
private static int CAPACITY = 10;
private int freeListTop = 0;
private int size = 0;
private int[] stackPointers = { -1, -1, -1 };
StackMFromArray() {
stackNodes = new StackNode[CAPACITY];
initFreeList();
}
private void initFreeList() {
for (int i = 0; i < CAPACITY; i++) {
stackNodes[i] = new StackNode(0, i + 1);
}
}
public void push(int stackNum, int value) throws Exception {
int freeIndex;
int currentStackTop = stackPointers[stackNum - 1];
freeIndex = getFreeNodeIndex();
StackNode n = stackNodes[freeIndex];
n.prev = currentStackTop;
n.value = value;
stackPointers[stackNum - 1] = freeIndex;
}
public StackNode pop(int stackNum) throws Exception {
int currentStackTop = stackPointers[stackNum - 1];
if (currentStackTop == -1) {
throw new Exception("UNDERFLOW");
}
StackNode temp = stackNodes[currentStackTop];
stackPointers[stackNum - 1] = temp.prev;
freeStackNode(currentStackTop);
return temp;
}
private int getFreeNodeIndex() throws Exception {
int temp = freeListTop;
if (size >= CAPACITY)
throw new Exception("OVERFLOW");
freeListTop = stackNodes[temp].prev;
size++;
return temp;
}
private void freeStackNode(int index) {
stackNodes[index].prev = freeListTop;
freeListTop = index;
size--;
}
public static void main(String args[]) {
// Test Driver
StackMFromArray mulStack = new StackMFromArray();
try {
mulStack.push(1, 11);
mulStack.push(1, 12);
mulStack.push(2, 21);
mulStack.push(3, 31);
mulStack.push(3, 32);
mulStack.push(2, 22);
mulStack.push(1, 13);
StackNode node = mulStack.pop(1);
node = mulStack.pop(1);
System.out.println(node.value);
mulStack.push(1, 13);
} catch (Exception e) {
e.printStackTrace();
}
}
}
For simplicity if not very efficient memory usage, you could[*] divide the array up into list nodes, add them all to a list of free nodes, and then implement your stacks as linked lists, taking nodes from the free list as required. There's nothing special about the number 3 in this approach, though.
[*] in a low-level language where memory can be used to store pointers, or if the stack elements are of a type such as int that can represent an index into the array.
There are many solutions to this problem already stated on this page. The fundamental questions, IMHO are:
How long does each push/pop operation take?
How much space is used? Specifically, what is the smallest number of elements that can be pushed to the three stacks to cause the data structure to run out of space?
As far as I can tell, each solution already posted on this page either can take up to linear time for a push/pop or can run out of space with a linear number of spaces still empty.
In this post, I will reference solutions that perform much better, and I will present the simplest one.
In order to describe the solution space more carefully, I will refer to two functions of a data structure in the following way:
A structure that takes O(f(n)) amortized time to perform a push/pop and does not run out of space unless the three stacks hold at least n - O(g(n)) items will be referred to as an (f,g) structure. Smaller f and g are better. Every structure already posted on this page has n for either the time or the space. I will demonstrate a (1,√n) structure.
This is all based on:
Michael L. Fredman and Deborah L. Goldsmith, "Three Stacks", in Journal of Algorithms, Volume 17, Issue 1, July 1994, Pages 45-70
An earlier version appeared in the 29th Annual Symposium on Foundations of Computer Science (FOCS) in 1988
Deborah Louise Goldsmith's PhD thesis from University of California, San Diego, Department of Electrical Engineering/Computer Science in 1987, "Efficient memory management for >= 3 stacks"
They show, though I will not present, a (log n/log S,S) structure for any S. This is equivalent to a (t, n1/t) structure for any t. I will show a simplified version that is a (1,√n) structure.
Divide the array up into blocks of size Θ(√n). The blocks are numbered from 1 to Θ(√n), and the number of a block is called its "address". An address can be stored in an array slot instead of a real item. An item within a given block can be referred to with a number less than O(√n), and such a number is called an index. An index will also fit in an array slot.
The first block will be set aside for storing addresses and indexes, and no other block will store any addresses or indexes. The first block is called the directory. Every non-directory block will either be empty or hold elements from just one of the three stacks; that is, no block will have two elements from different stacks. Additionally, every stack will have at most one block that is partially filled -- all other blocks associated with a stack will be completely full or completely empty.
As long as there is an empty block, a push operation will be permitted to any stack. Pop operations are always permitted. When a push operation fails, the data structure is full. At that point, the number of slots not containing elements from one of the stacks is at most O(√n): two partially-filled blocks from the stacks not being pushed to, and one directory block.
Every block is ordered so that the elements closer to the front of the block (lower indexes) are closer to the bottom of the stack.
The directory holds:
Three addresses for the blocks at the top of the three stacks, or 0 if there are no blocks in a particular stack yet
Three indexes for the element at the top of the three stacks, or 0 if there are no items in a particular stack yet.
For each full or partially full block, the address of the block lower than it in the same stack, or 0 if it is the lowest block in the stack.
The address of a free block, called the leader block, or 0 if there are no free blocks
For each free block, the address of another free block, or 0 if there are no more free blocks
These last two constitute a stack, stored as a singly-linked list, of free blocks. That is, following the addresses of free blocks starting with the leader block will give a path through all the free blocks, ending in a 0.
To push an item onto a stack, find its top block and top element within that block using the directory. If there is room in that block, put the item there and return.
Otherwise, pop the stack of free blocks by changing the address of the leader block to the address of the next free block in the free block stack. Change the address and index for the stack to be the address of the just-popped free block and 1, respectively. Add the item to the just-popped block at index 1, and return.
All operations take O(1) time. Pop is symmetric.
A variant on an earlier answer: stack #1 grows from the left, and stack #2 grows from the right.
Stack #3 is in the center, but the elements grow in alternate order to the left and right. If N is the center index, the stack grows as: N, N-1, N+1, N-2, N+2, etc. A simple function converts the stack index to an array index.
I think you should divide array in 3 pieces, making head of first stack at 0, head of second stack at n/3, head of 3rd stack at n-1.
so implement push operation on :
first & second stack make i++ and for 3rd stack make i--;
If you encounter that first stack have no space to push, shift 2nd stack k/3 positions forward. Where k is the number of positions left to be filled in array.
If you encounter that second stack have no space to push, shift 2nd stack 2*k/3 positions backward. Where k is the number of positions left to be filled in array.
If you encounter that third stack have no space to push, shift 2nd stack 2*k/3 positions backward. Where k is the number of positions left to be filled in array.
We are shifting k/3 and 2*k/3 when no space is left so that after shifting of middle stack, each stack have equal space available for use.
Store the stack in the area in such way when first stack goes into index 0, then 0+3=3, then 3+3=6...; the second one goes into indexes 1, 1+3=4, 4+3=7...; the the third one goes into indexes 2, 2+3=5, 5+3=8
So if we mark the first stack elements with a, as one with b and there with c we get:
a1 b1 c1 a2 b2 c2 a3 b3 c3...
There could be gaps but we always know the top indexes which are stored in 3-element topIndex array.
Partitioning the array into 3 parts in not a good idea as it will give overflow if there are many elements in stack1 and very few elements in the other two.
My idea:
Keep three pointers ptr1, ptr2, ptr3 to point the top element of respective stacks.
Initially ptr1 = ptr2 = ptr3 = -1;
In the array, the even indexed element will store the value and odd indexed element will store the index of previous element of that stack.
For example,
s1.push(1);
s2.push(4);
s3.push(3);
s1.push(2);
s3.push(7);
s1.push(10);
s1.push(5);
then our array looks like:
1, -1, 4, -1, 3, -1, 2, 0, 7, 4, 10, 6, 5, 10
and the values of pointers are:
ptr1 = 12, ptr2 = 2 , ptr3 = 8
Solution: Implementing two stacks is easy.
First stack grows from start to end while second one grows from end to start.
Overflow for any of them will not happen unless there really is no space left on the array.
For three stacks, following is required:
An auxiliary array to maintain the parent for each node.
Variables to store the current top of each stack.
With these two in place, data from all the stacks can be interspersed in the original array and one can still do push/pop/size operations for all the stacks.
When inserting any element, insert it at the end of all the elements in the normal array.
Store current-top of that stack as parent for the new element (in the parents' array) and update current-top to the new position.
When deleting, insert NULL in the stacks array for the deleted element and reset stack-top for that stack to the parent.
When the array is full, it will have some holes corresponding to deleted elements.
At this point, either the array can be compacted to bring all free space together or a linear search can be done for free space when inserting new elements.
for further details refer this link:- https://coderworld109.blogspot.in/2017/12/how-to-implement-3-stacks-with-one-array.html
Here is my solution of N stacks in a single array.
Some constraints will be here.
that size of the array will not be less than of the number of stacks.
I have used to customize exception class StackException in my solution. You can change the exception class for running the programme.
For multiple stacks in an array, I managed pointers to another array.
package com.practice.ds.stack;
import java.util.Scanner;
import java.util.logging.Logger;
/** Multiple stacks in a single array */
public class MultipleStack {
private static Logger logger = Logger.getLogger("MultipleStack");
private int[] array;
private int size = 10;
private int stackN = 1;
private int[] pointer;
public MultipleStack() {
this.array = new int[size];
this.pointer = new int[1];
}
public MultipleStack(int size, int stackN) throws StackException {
if (stackN > size)
throw new StackException("Input mismatch ! no of stacks can't be larger than size ");
this.size = size;
this.stackN = stackN;
init();
}
private void init() {
if (size <= 0) {
logger.info("Initialize size is " + size + " so assiginig defalt size ");
this.size = 10;
}
if (stackN < 1) {
logger.info("Initialize no of Stack is " + size + " so assiginig defalt");
this.stackN = 1;
}
this.array = new int[size];
this.pointer = new int[stackN];
initializePointer();
}
private void initializePointer() {
for (int i = 0; i < stackN; i++)
pointer[i] = (int)(i * Math.ceil(size / stackN) - 1);
}
public void push(int item, int sn) throws StackException {
if (full(sn))
throw new StackException(sn + " is overflowed !");
int stkPointer = pointer[sn - 1];
array[++stkPointer] = item;
pointer[sn - 1] = stkPointer;
}
public void pop(int sn) throws StackException {
if (empty(sn))
throw new StackException(sn + " is underflow !");
int peek = peek(sn);
System.out.println(peek);
pointer[sn - 1] = --pointer[sn - 1];
}
public int peek(int sn) throws StackException {
authenticate(sn);
return array[pointer[sn - 1]];
}
public boolean empty(int sn) throws StackException {
authenticate(sn);
return pointer[sn - 1] == (int)(((sn - 1) * Math.ceil(size / stackN)) - 1);
}
public boolean full(int sn) throws StackException {
authenticate(sn);
return sn == stackN ? pointer[sn - 1] == size - 1 : pointer[sn - 1] == (int)((sn) * Math.ceil(size / stackN)) - 1;
}
private void authenticate(int sn) throws StackException {
if (sn > stackN || sn < 1)
throw new StackException("No such stack found");
}
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
System.out.println("Define size of the stack");
int size = scanner.nextInt();
System.out.println("total number of stacks");
int stackN = scanner.nextInt();
MultipleStack stack = new MultipleStack(size, stackN);
boolean exit = false;
do {
System.out.println("1. Push");
System.out.println("2. Pop");
System.out.println("3. Exit");
System.out.println("Choice");
int choice = scanner.nextInt();
switch (choice) {
case 1:
try {
System.out.println("Item : ");
int item = scanner.nextInt();
System.out.println("Stack Number : ");
int stk = scanner.nextInt();
stack.push(item, stk);
} catch (Exception e) {
e.printStackTrace();
}
break;
case 2:
try {
System.out.println("Stack Number : ");
int stk = scanner.nextInt();
stack.pop(stk);
} catch (Exception e) {
e.printStackTrace();
}
break;
case 3:
exit = true;
break;
default:
System.out.println("Invalid choice !");
break;
}
} while (!exit);
} catch (Exception e) {
e.printStackTrace();
}
}
}
We can generalize it to K stacks in one Array. Basic idea is to:
Maintain a PriorityQueue as a min heap of currently free indexes in the allocation array.
Maintain an array of size K, that holds the top of the stack, for each of the stacks.
Create a Data class with 1) Value 2) Index of Prev element in the allocation array 3) Index of current element being pushed in the
allocation array
Maintain an allocation array of type Data
Refer the code for a working sample implementation.
import java.util.*;
public class Main
{
// A Java class to represent k stacks in a single array of size n
public static final class KStack {
/**
* PriorityQueue as min heap to keep track of the next free index in the
* backing array.
*/
private final PriorityQueue<Integer> minHeap = new PriorityQueue<>((a,b) -> (a - b));
/**
* Keeps track of the top of the stack of each of the K stacks
*/
private final Data index[];
/**
* Backing array to hold the data of K stacks.
*/
private final Data array[];
public KStack(int noOfStacks, int sizeOfBackingArray) {
index = new Data[noOfStacks];
array = new Data[sizeOfBackingArray];
for(int i =0; i< sizeOfBackingArray; i++) {
minHeap.add(i);
}
}
public void push(int val, int stackNo) {
if(minHeap.isEmpty()) {
return;
}
int nextFreeIdx = minHeap.poll();
Data tos = index[stackNo];
if(tos == null) {
tos = new Data(val, -1 /* Previous elemnet's idx*/, nextFreeIdx
/* This elemnent's idx in underlying array*/);
} else {
tos = new Data(val, tos.myIndex, nextFreeIdx);
}
index[stackNo] = tos;
array[nextFreeIdx] = tos;
}
public int pop(int stackNo) {
if(minHeap.size() == array.length) {
return -1; // Maybe throw Exception?
}
Data tos = index[stackNo];
if(tos == null) {
return -1; // Maybe throw Exception?
}
minHeap.add(tos.myIndex);
array[tos.myIndex] = null;
int value = tos.value;
if(tos.prevIndex == -1) {
tos = null;
} else {
tos = array[tos.prevIndex];
}
index[stackNo] = tos;
return value;
}
}
public static final class Data {
int value;
int prevIndex;
int myIndex;
public Data(int value, int prevIndex, int myIndex) {
this.value = value;
this.prevIndex = prevIndex;
this.myIndex = myIndex;
}
#Override
public String toString() {
return "Value: " + this.value + ", prev: " + this.prevIndex + ", myIndex: " + myIndex;
}
}
// Driver program
public static void main(String[] args)
{
int noOfStacks = 3, sizeOfBackingArray = 10;
KStack ks = new KStack(noOfStacks, sizeOfBackingArray);
// Add elements to stack number 1
ks.push(11, 0);
ks.push(9, 0);
ks.push(7, 0);
// Add elements to stack number 3
ks.push(51, 2);
ks.push(54, 2);
// Add elements to stack number 2
ks.push(71, 1);
ks.push(94, 1);
ks.push(93, 1);
System.out.println("Popped from stack 3: " + ks.pop(2));
System.out.println("Popped from stack 3: " + ks.pop(2));
System.out.println("Popped from stack 3: " + ks.pop(2));
System.out.println("Popped from stack 2: " + ks.pop(1));
System.out.println("Popped from stack 1: " + ks.pop(0));
}
}
Dr. belisarius's answer explains the basic algorithm, but doesn't go in the details, and as we know, the devil is always in the details. I coded up a solution in Python 3, with some explanation and a unit test. All operations run in constant time, as they should for a stack.
# One obvious solution is given array size n, divide up n into 3 parts, and allocate floor(n / 3) cells
# to two stacks at either end of the array, and remaining cells to the one in the middle. This strategy is not
# space efficient because even though there may be space in the array, one of the stack may overflow.
#
# A better approach is to have two stacks at either end of the array, the left one growing on the right, and the
# right one growing on the left. The middle one starts at index floor(n / 2), and grows at both ends. When the
# middle stack size is even, it grows on the right, and when it's odd, it grows on the left. This way, the middle
# stack grows evenly and minimizes the changes of overflowing one of the stack at either end.
#
# The rest is pointer arithmetic, adjusting tops of the stacks on push and pop operations.
class ThreeStacks:
def __init__(self, n: int):
self._arr: List[int] = [0] * n
self._tops: List[int] = [-1, n, n // 2]
self._sizes: List[int] = [0] * 3
self._n = n
def _is_stack_3_even_size(self):
return self._sizes[2] % 2 == 0
def _is_stack_3_odd_size(self):
return not self._is_stack_3_even_size()
def is_empty(self, stack_number: int) -> bool:
return self._sizes[stack_number] == 0
def is_full(self, stack_number: int) -> bool:
if stack_number == 0 and self._is_stack_3_odd_size():
return self._tops[stack_number] == self._tops[2] - self._sizes[2]
elif stack_number == 1 and self._is_stack_3_even_size():
return self._tops[stack_number] == self._tops[2] + self._sizes[2]
return (self._is_stack_3_odd_size() and self._tops[0] == self._tops[2] - self._sizes[2]) or \
(self._is_stack_3_even_size() and self._tops[1] == self._tops[2] + self._sizes[2])
def pop(self, stack_number: int) -> int:
if self.is_empty(stack_number):
raise RuntimeError(f"Stack : {stack_number} is empty")
x: int = self._arr[self._tops[stack_number]]
if stack_number == 0:
self._tops[stack_number] -= 1
elif stack_number == 1:
self._tops[stack_number] += 1
else:
if self._is_stack_3_even_size():
self._tops[stack_number] += (self._sizes[stack_number] - 1)
else:
self._tops[stack_number] -= (self._sizes[stack_number] - 1)
self._sizes[stack_number] -= 1
return x
def push(self, item: int, stack_number: int) -> None:
if self.is_full(stack_number):
raise RuntimeError(f"Stack: {stack_number} is full")
if stack_number == 0:
self._tops[stack_number] += 1
elif stack_number == 1:
self._tops[stack_number] -= 1
else:
if self._is_stack_3_even_size():
self._tops[stack_number] += self._sizes[stack_number]
else:
self._tops[stack_number] -= self._sizes[stack_number]
self._arr[self._tops[stack_number]] = item
self._sizes[stack_number] += 1
def __repr__(self):
return str(self._arr)
Test:
def test_stack(self):
stack = ThreeStacks(10)
for i in range(3):
with pytest.raises(RuntimeError):
stack.pop(i)
for i in range(1, 4):
stack.push(i, 0)
for i in range(4, 7):
stack.push(i, 1)
for i in range(7, 11):
stack.push(i, 2)
for i in range(3):
with pytest.raises(RuntimeError):
stack.push(1, i)
assert [stack.pop(i) for i in range(3)] == [3, 6, 10]
assert [stack.pop(i) for i in range(3)] == [2, 5, 9]
assert [stack.pop(i) for i in range(3)] == [1, 4, 8]
for i in range(2):
assert stack.is_empty(i)
assert not stack.is_empty(2)
assert stack.pop(2) == 7
assert stack.is_empty(2)
This is a very common interview question "Implement 3 stacks using a single Array or >List".
Here is my solution-
Approach 1- Go for a fixed division of an array means if we divide our array into 3 equal parts and push the elements of an array
into three fixed-sized stacks.
For stack 1, use [0,n/3]
For stack 2, use [n/3,2n/3]
For stack 3, use [2n/3,n]. The problem with this approach is that we may face a condition where the size of an array may be
greater than the size of the stack ie. Stack Overflow condition. So,
we must take care of special cases and edge cases like this. now go
for 2nd approach.
Approach 2- Flexible Division, In the first approach we face a condition where the size of an array may be greater than the size of
the stack ie the Stack overflow condition. we can overcome this
problem by doing a flexible division of the stack. while adding
elements to the stack, when one stack exceeds the initial capacity,
shift the elements to the next stack. So, this way we can approach
this problem.
Here's my solution for it in C# -
/* Program: Implement 3 stacks using a single array
*
* Date: 12/26/2015
*/
using System;
namespace CrackingTheCodingInterview
{
internal class Item
{
public object data;
public int prev;
}
/// <summary>
/// Class implementing 3 stacks using single array
/// </summary>
public class Stacks
{
/// <summary>
/// Pushing an element 'data' onto a stack 'i'
/// </summary>
public void Push(int i, object d)
{
i--;
if (available != null)
{
int ava = (int)available.DeleteHead();
elems[ava].data = d;
elems[ava].prev = top[i];
top[i] = ava;
}
else
{
Console.WriteLine("Array full. No more space to enter!");
return;
}
}
/// <summary>
/// Popping an element from stack 'i'
/// </summary>
public object Pop(int i)
{
i--;
if (top[i] != -1)
{
object popVal = elems[top[i]].data;
int prevTop = elems[top[i]].prev;
elems[top[i]].data = null;
elems[top[i]].prev = -1;
available.Insert(top[i]);
top[i] = prevTop;
return popVal;
}
else
{
Console.WriteLine("Stack: {0} empty!", i);
return null;
}
}
/// <summary>
/// Peeking top element of a stack
/// </summary>
public object Peek(int i)
{
i--;
if (top[i] != -1)
{
return elems[top[i]].data;
}
else
{
Console.WriteLine("Stack: {0} empty!", i);
return null;
}
}
/// <summary>
/// Constructor initializing array of Nodes of size 'n' and the ability to store 'k' stacks
/// </summary>
public Stacks(int n, int k)
{
elems = new Item[n];
top = new int[k];
for (int i = 0; i < k; i++)
{
top[i] = -1;
}
for (int i = 0; i < n; i++)
{
elems[i] = new Item();
elems[i].data = null;
elems[i].prev = -1;
}
available = new SinglyLinkedList();
for (int i = n - 1; i >= 0; i--)
{
available.Insert(i);
}
}
private Item[] elems;
private int[] top;
private SinglyLinkedList available;
}
internal class StacksArrayTest
{
static void Main()
{
Stacks s = new Stacks(10, 3);
s.Push(1, 'a');
s.Push(1, 'b');
s.Push(1, 'c');
Console.WriteLine("After pushing in stack 1");
Console.WriteLine("Top 1: {0}", s.Peek(1));
s.Push(2, 'd');
s.Push(2, 'e');
s.Push(2, 'f');
s.Push(2, 'g');
Console.WriteLine("After pushing in stack 2");
Console.WriteLine("Top 1: {0}", s.Peek(1));
Console.WriteLine("Top 2: {0}", s.Peek(2));
s.Pop(1);
s.Pop(2);
Console.WriteLine("After popping from stack 1 and 2");
Console.WriteLine("Top 1: {0}", s.Peek(1));
Console.WriteLine("Top 2: {0}", s.Peek(2));
s.Push(3, 'h');
s.Push(3, 'i');
s.Push(3, 'j');
s.Push(3, 'k');
s.Push(3, 'l');
Console.WriteLine("After pushing in stack 3");
Console.WriteLine("Top 3: {0}", s.Peek(3));
Console.ReadLine();
}
}
}
Output:
After pushing in stack 1
Top 1: c
After pushing in stack 2
Top 1: c
Top 2: g
After popping from stack 1 and 2
Top 1: b
Top 2: f
After pushing in stack 3
Top 3: l
I refer to this post for coding it - http://codercareer.blogspot.com/2013/02/no-39-stacks-sharing-array.html
package job.interview;
import java.util.Arrays;
public class NStack1ArrayGen<T> {
T storage[];
int numOfStacks;
Integer top[];
public NStack1ArrayGen(int numOfStks, T myStorage[]){
storage = myStorage;
numOfStacks = numOfStks;
top = new Integer[numOfStks];
for(int i=0;i<numOfStks;i++){top[i]=-1;}
}
public void push(int stk_indx, T value){
int r_indx = stk_indx -1;
if(top[r_indx]+numOfStacks < storage.length){
top[r_indx] = top[r_indx] < 0 ? stk_indx-1 : top[r_indx]+numOfStacks;
storage[top[r_indx]] = value;
}
}
public T pop(int stk_indx){
T ret = top[stk_indx-1]<0 ? null : storage[top[stk_indx-1]];
top[stk_indx-1] -= numOfStacks;
return ret;
}
public void printInfo(){
print("The array", Arrays.toString(storage));
print("The top indices", Arrays.toString(top));
for(int j=1;j<=numOfStacks;j++){
printStack(j);
}
}
public void print(String name, String value){
System.out.println(name + " ==> " + value);
}
public void printStack(int indx){
String str = "";
while(top[indx-1]>=0){
str+=(str.length()>0 ? "," : "") + pop(indx);
}
print("Stack#"+indx,str);
}
public static void main (String args[])throws Exception{
int count=4, tsize=40;
int size[]={105,108,310,105};
NStack1ArrayGen<String> mystack = new NStack1ArrayGen<String>(count,new String[tsize]);
for(int i=1;i<=count;i++){
for(int j=1;j<=size[i-1];j++){
mystack.push(i, "stk"+i+"_value"+j);
}
}
}
}
This prints:
The array ==> [stk1_value1, stk2_value1, stk3_value1, stk4_value1, stk1_value2, stk2_value2, stk3_value2, stk4_value2, stk1_value3, stk2_value3, stk3_value3, stk4_value3, stk1_value4, stk2_value4, stk3_value4, stk4_value4, stk1_value5, stk2_value5, stk3_value5, stk4_value5, stk1_value6, stk2_value6, stk3_value6, stk4_value6, stk1_value7, stk2_value7, stk3_value7, stk4_value7, stk1_value8, stk2_value8, stk3_value8, stk4_value8, stk1_value9, stk2_value9, stk3_value9, stk4_value9, stk1_value10, stk2_value10, stk3_value10, stk4_value10]
The top indices ==> [36, 37, 38, 39]
Stack#1 ==> stk1_value10,stk1_value9,stk1_value8,stk1_value7,stk1_value6,stk1_value5,stk1_value4,stk1_value3,stk1_value2,stk1_value1
Stack#2 ==> stk2_value10,stk2_value9,stk2_value8,stk2_value7,stk2_value6,stk2_value5,stk2_value4,stk2_value3,stk2_value2,stk2_value1
Stack#3 ==> stk3_value10,stk3_value9,stk3_value8,stk3_value7,stk3_value6,stk3_value5,stk3_value4,stk3_value3,stk3_value2,stk3_value1
Stack#4 ==> stk4_value10,stk4_value9,stk4_value8,stk4_value7,stk4_value6,stk4_value5,stk4_value4,stk4_value3,stk4_value2,stk4_value1
enum stackId{LEFT, MID, RIGHT };
class threeStacks {
int* arr;
int leftSize;
int rightSize;
int midSize;
int mid;
int maxSize;
public:
threeStacks(int n):leftSize(0), rightSize(0), midSize(0), mid(n/2), maxSize(n)
{
arr = new int[n];
}
void push(stackId sid, int val){
switch(sid){
case LEFT:
pushLeft(val);
break;
case MID:
pushMid(val);
break;
case RIGHT:
pushRight(val);
}
}
int pop(stackId sid){
switch(sid){
case LEFT:
return popLeft();
case MID:
return popMid();
case RIGHT:
return popRight();
}
}
int top(stackId sid){
switch(sid){
case LEFT:
return topLeft();
case MID:
return topMid();
case RIGHT:
return topRight();
}
}
void pushMid(int val){
if(midSize+leftSize+rightSize+1 > maxSize){
cout << "Overflow!!"<<endl;
return;
}
if(midSize % 2 == 0){
if(mid - ((midSize+1)/2) == leftSize-1){
//left side OverFlow
if(!shiftMid(RIGHT)){
cout << "Overflow!!"<<endl;
return;
}
}
midSize++;
arr[mid - (midSize/2)] = val;
}
else{
if(mid + ((midSize+1)/2) == (maxSize - rightSize)){
//right side OverFlow
if(!shiftMid(LEFT)){
cout << "Overflow!!"<<endl;
return;
}
}
midSize++;
arr[mid + (midSize/2)] = val;
}
}
int popMid(){
if(midSize == 0){
cout << "Mid Stack Underflow!!"<<endl;
return -1;
}
int val;
if(midSize % 2 == 0)
val = arr[mid - (midSize/2)];
else
val = arr[mid + (midSize/2)];
midSize--;
return val;
}
int topMid(){
if(midSize == 0){
cout << "Mid Stack Underflow!!"<<endl;
return -1;
}
int val;
if(midSize % 2 == 0)
val = arr[mid - (midSize/2)];
else
val = arr[mid + (midSize/2)];
return val;
}
bool shiftMid(stackId dir){
int freeSpace;
switch (dir){
case LEFT:
freeSpace = (mid - midSize/2) - leftSize;
if(freeSpace < 1)
return false;
if(freeSpace > 1)
freeSpace /= 2;
for(int i=0; i< midSize; i++){
arr[(mid - midSize/2) - freeSpace + i] = arr[(mid - midSize/2) + i];
}
mid = mid-freeSpace;
break;
case RIGHT:
freeSpace = maxSize - rightSize - (mid + midSize/2) - 1;
if(freeSpace < 1)
return false;
if(freeSpace > 1)
freeSpace /= 2;
for(int i=0; i< midSize; i++){
arr[(mid + midSize/2) + freeSpace - i] = arr[(mid + midSize/2) - i];
}
mid = mid+freeSpace;
break;
default:
return false;
}
}
void pushLeft(int val){
if(midSize+leftSize+rightSize+1 > maxSize){
cout << "Overflow!!"<<endl;
return;
}
if(leftSize == (mid - midSize/2)){
//left side OverFlow
if(!shiftMid(RIGHT)){
cout << "Overflow!!"<<endl;
return;
}
}
arr[leftSize] = val;
leftSize++;
}
int popLeft(){
if(leftSize == 0){
cout << "Left Stack Underflow!!"<<endl;
return -1;
}
leftSize--;
return arr[leftSize];
}
int topLeft(){
if(leftSize == 0){
cout << "Left Stack Underflow!!"<<endl;
return -1;
}
return arr[leftSize - 1];
}
void pushRight(int val){
if(midSize+leftSize+rightSize+1 > maxSize){
cout << "Overflow!!"<<endl;
return;
}
if(maxSize - rightSize - 1 == (mid + midSize/2)){
//right side OverFlow
if(!shiftMid(LEFT)){
cout << "Overflow!!"<<endl;
return;
}
}
rightSize++;
arr[maxSize - rightSize] = val;
}
int popRight(){
if(rightSize == 0){
cout << "Right Stack Underflow!!"<<endl;
return -1;
}
int val = arr[maxSize - rightSize];
rightSize--;
return val;
}
int topRight(){
if(rightSize == 0){
cout << "Right Stack Underflow!!"<<endl;
return -1;
}
return arr[maxSize - rightSize];
}
};
Python
class Stack:
def __init__(self):
self.pos_1 = 0
self.pos_2 = 1
self.pos_3 = 2
self.stack = [None, None, None]
def pop_1(self):
if self.pos_2 - 1 > 0:
to_ret = self.stack.pop(self.pos_1)
self.pos_2 -= 1
self.pos_3 -= 1
return to_ret
def push_1(self, value):
self.stack.insert(self.pos_1, value)
self.pos_2 += 1
self.pos_3 += 1
return None
def pop_2(self):
if self.pos_2 - 1 < self.pos_3:
to_ret = self.stack.pop(self.pos_2)
self.pos_3 -= 1
return to_ret
def push_2(self, value):
self.stack.insert(self.pos_2, value)
self.pos_3 += 1
return None
def pop_3(self):
if self.pos_3 - 1 > self.pos_2:
to_ret = self.stack.pop(self.pos_3)
return to_ret
def push_3(self, value):
self.stack.insert(self.pos_3, value)
return None
if __name__ == "__main__":
stack = Stack()
stack.push_2(22)
stack.push_1(1)
stack.push_1(2)
print stack.pop_1()
print stack.pop_1()
print stack.pop_2()
prints: 2 1 22

Resources