views:

465

answers:

7

I have a stack which contains some integer data. I want to find out the min value from Stack in O(1) time. Any idea?

PS: There is no ordering (increasing/decreasing) of data in Stack.

Thanks,

Naveen

+2  A: 

A stack by definition is push/pop (LIFO) data structure. You can't!

AraK
Actually you can find the minimum value on a Stack, if you use some other data structure (e.g. a second Stack) to hold the popped values. But N pops + N comparisons + N pushes is O(N).
Stephen C
@Stephen I said "You can't!" do "O(1) time" :)
AraK
+2  A: 

O(n) is the best you're gonna do - you'd have to check each one of the values and compare them to the aggregator minimum, otherwise how would you know you got the lowest?

If you want, you can store the minimum as the values are added, making the pushes more expensive for the benefit of an O(1) read (of the pre-calculated minimum), but that's it.

uosɐſ
The values are already there on the Stack. I only have to find out the minimum value in the Stack.
Naveen
@Naveen: the answer is still the same. There are N values on the stack and you have to look at all of them to figure out which is the smallest. That is N comparisons, so the computation is at best O(N).
Stephen C
I believe you meant to say: "making the pops more expensive", because in your approach, popping might cause you to have to search for a min. But as already suggested, you can use two stacks.
Tom
also, @Stephen C... you mean N - 1 comparisons... still O(n) though :-).
Tom
+1  A: 

I am not sure why you expect to do this in constant time for arbitrary length. The best you will be able to do is O(n)

hhafez
Yes, I know it can be done in O(n) time. I just want to know if it is possible to do in O(1) time also.
Naveen
He said, and I quote, "The best you will be able to do is O(n)." So no, you can't do it in O(1).
Chris Lutz
This answer doesn't really answer the question. It is answering the question of "what is the big-o for finding the min in a list n elements". It doesn't say anything about the stack data structure or how it can be modified.
Tom
Maybe I was thinking too much in the square so to speak ;) but I was answer the question strictly "can you find the min of stack in constant time" If all you have is that stack then the answer is no.
hhafez
+15  A: 

Use two stacks. One is the data, one is the minimums. When you push onto the data stack, push the new minimum onto the minimums stack (the new minimum is the min of the item you're pushing and whatever is currently on the top of the minimums stack), and when you pop, pop off of both stacks (so that the two stacks always have the same number of elements). To find the minimum element, just look at the top of the minimums stack.

Pushing, popping and finding the min value are O(1).

ESRogs
bravo :-). beat me to it... and everyone said it was impossible!
Tom
I wish I could +1 this answer again. I bet you'll earn some badges from this one :-).
Tom
@wrang-wrang, why?
Tom
A better implementation would keep the minimums stack at 1 element, no matter how many were added to the other, but that's only if you need the minimum for the whole stack, and not for any "substack" in the stack.
Chris Lutz
@wrang wrang: Push 1 on regularStack, Push 1 on minStack. Push 2 on regularStack, push 1 on minStack. Push 3 on regularStack, push 1 on minstack... if you pop once or twice (off both stacks), you will still have the correct min value on the top of the minStack. Make sense?
Tom
@Chris Lutz: can you clarify? You can't keep one item on the min stack because that is the same as storing the minimum in a variable... and if the min gets popped off the regular stack, you get stuck having to search for a new minimum.
Tom
I misunderstood the algorithm description. Yes, it works.
wrang-wrang
@Tom - Push first item on the main stack. Since there is nothing in the min stack, the minimum is now that item, so push it on the main stack. Push second item on the main stack. Since there is something in the min stack, pop it, compare it to the item just pushed on the main stack, and push the smaller of the two. Now the min stack has one item - the minimum of the two items in the main stack. Rinse, lather, repeat as many times as you want.
Chris Lutz
@Chris Lutz: Ok, so now how about pushing in this order: 5, 4, 3, 2, 1. Are you saying that after all those pushes, the min stack will have 1 item, namely, the number 1? Then when you pop, you need to search through the stack to find that 2 is the min. That's why you need to keep all the mins at each push.
Tom
Why use term min stack? Keep one min item :-)
Learner
@Chris Lutz: Is this what you meant by "not for any "substack"". Do you agree with me that if you want to support popping and being able to find the min that you must keep all mins?
Tom
@learner: because you need to keep track of the min item at every push to avoid searching for a new min after you pop off the min.
Tom
@Tom i think you can check and may modify the min at each push and pop.
Learner
@Tom - Yeah, that's what I meant by "not for any substack." I didn't know the technical term for a "substack." I agree that to support popping on the stack you must keep a stack of minimums, as you said. But for what it's worth, I don't think this is one of those "trick" (i.e. interview) questions that involve using two stacks, and I don't think tricks like that should be used in production code.
Chris Lutz
@learner: of course you can "modify the the min at each push and pop"... the question is, how much does that cost? Suppose I push on the stack the following numbers, in this order: 2, 5, 5, 5, 5, 5, 1. The min is 1 right now. After I pop, the min is 2. The min stack would help you keep track of this because it would look like this: 2, 2, 2, 2, 2, 2, 1. Make sense?
Tom
@Chris Lutz: I don't think this is "a trick"... although it is clever. Why wouldn't you use it in production? Are you saying that if you needed to support these operations in production code, you would incur the O(n) cost to find the min when you could do it in O(1), without even increasing the amount of space by another factor??? This is just the correct way to solve this particular problem and is find in production. In production code, you would make a class that encapsulated the two stacks put exposed the stack interface along with findMin().
Tom
@Tom, Yes this makes sense. The implementer has to decide which to follow as in one he is loosing space and other his push and pop are much more expensive..
Learner
@learner: correct :-). As usual, there is a tradeoff and it depends on what you need. But jfyi, only the pops are more expensive in the other way of doing it, because only popping forces you to find a new min (when you happen to pop off the min).
Tom
To everyone: you could save some space... in the min stack... rather than storing the min... store the min value, and a "count" that says how many times it appears in the stack, in a row. That way, if you have 10 ones in a row, you only use 1 stack node: (1, 10). Then when you pop, change the node to (1, 9). This will save some space - but the other way most likely won't kill your app.
Tom
This is far far far from a trick. It is what programmers do every day. If I was worried about the cost of two pushes(not memory size - just the cacheline accesses to two different areas of memory) I would push a struct{ int value;int min;}; The algorithm is still essentially the same as ESRogs' solution (BTW nice ESRogs) but reduces the address calculations and accesses only one cacheline per item. Not only that now one can augment the pushed struct to add maximum without adding another stack.
pgast
I voted this up and I think it is a very creative solution. It is an interesting improvement on the naive O(n) setup (if memory is cheap), BUT, in the interest of a complete discussion, I think that this shouldn't be considered O(1). This algorithm may /approach/ O(1) because it is amortizing the cost of the comparisons over all minimum value queries. But querying for the value just once still costs O(n).But seriously, I like the algorithm.
uosɐſ
@Jason, I'm not sure what you're talking about. There's no amortization going on here. Each push, pop, and min query is O(1).
ESRogs
yes, the push and pop are O(1), but they include additional logic used only for the purposes of finding the minimum. So the way I'm looking at it, the functionality of finding the minimum is just being done over the course of pushing and popping the stack, the same number of additional comparisons are being made solely for the purposes of having the minimum available. The push or pop of the data value is otherwise independent of that calculation. So you'll have done approximately n comparisons anyway for the first minimum query. n/2 for the second, n/3 for the third ...
uosɐſ
@Jason: That is the wrong way to look at "amortization". I understand the point you are getting at - but it doesn't fit the technical description of amortization. Of course overall you are doing more work with this approach. But to say it is O(1) means the following: As the stack size grows (we call the size "n"), the cost of the push/pop/findMin operations does not grow. In other words, the "cost" in some unit for any of those operations is independent of the stack size. That is what is means to be O(1).
Tom
@Jason: In order to be amortized O(1), it (in non-tech terms) means that for SOME execution of the operation in interest, you will do more work than the amortized cost... an example would be this: if an operation is "usually" O(1), but occasionally depends on "n" and you do O(n) work... but you can guarantee you do O(n) work about every n ops. then over the course of n ops the amount of work you did is essentially like O(1). When you think of amortization, think of adds to a vector. The adds are O(1) except in the case you don't have more space. Then you double the space which takes O(n) work.
Tom
@Tom Well said.
ESRogs
+1  A: 

You'll probably want some kind of priority heap if you want to always pop the least element. If you want to pop what was last pushed, but be able to know the order of the elements remaining in the stack, some kind of search tree e.g. red-black will support deletion of an element from an arbitrary position (your stack would have a pointer to the tree node so when you pop you can find it).

If you only need to know the minimum (or max) remaining in the stack then ESRogs' is optimal.

wrang-wrang
A: 

Here is the Python implementation of ESRogs algorithm using lists as stacks:

class ConstantStack:
    def __init__(self):
        self.stack = []
        self.min_stack = []
    def push(self,item):
        self.stack.append(item)
        if len(self.min_stack) == 0:
            self.min_stack.append(item)
            return
        # Get the smaller item between the pushed item and the top of the stack
        smallest = min(item,self.min_stack[-1])
        self.min_stack.append(smallest)
    def pop(self):
        self.min_stack.pop()
        return self.stack.pop()
    def min(self):
        # NOTE: min_stack[-1] is equivalent to peek()
        return self.min_stack[-1]

Here is an example of its usage:

>>> s = ConstantStack()
>>> s.push(3)
>>> s.push(7)
>>> s.push(6)
>>> s.push(1)
>>> s.min()
1
>>> s.pop()
1
>>> # Now that 1 is gone, 3 is the next smallest
>>> s.min()
3
>>> s.pop()
6
>>> # 6 was popped but 3 still remains the smallest
>>> s.min()
3
>>> s.pop()
7
>>> s.min()
3
>>> s.pop()
3
jkupferman
A: 

define STACKSIZE 50

typedef struct stack { int item[STACKSIZE]; int top; }MULSTACKEX;

void InitStack(MULSTACKEX &st) { st.item[STACKSIZE] = 0; st.top = -1; }

void Push(MULSTACKEX &st1, MULSTACKEX &st2, int elem) { if(st1.top == -1) { st1.top++; st1.item[st1.top] = elem;

 st2.top++;
 st2.item[st2.top] = elem;
}
else
{
 st1.top++;
 st1.item[st1.top] = elem;

 if(elem < st2.item[st2.top])
 {
  st2.top++;
  st2.item[st2.top] = elem;
 }
}

}

void Display(MULSTACKEX &st1, MULSTACKEX &st2) { cout<<"stack1 elements: "<"; }

cout<<endl;
cout<<"stack2 elements: "<<endl;
for(int i = 0; i <= st2.top; i++)
{
 cout<<st2.item[i]<<"->";
}

}

int Pop(MULSTACKEX &st1, MULSTACKEX &st2) { int elem = 0; if(st1.item[st1.top] == st2.item[st2.top]) { elem = st2.item[st2.top]; st2.top--;

 elem = st1.item[st1.top];
 st1.top--;
}
else
{
 elem = st1.item[st1.top];
 st1.top--;
}

return elem;

} int FindMin(MULSTACKEX &st2) { int elem = st2.item[st2.top]; return elem; }

int _tmain(int argc, TCHAR argv[]) { MULSTACKEX stack1, stack2;

InitStack(stack1); 
InitStack(stack2);


Push(stack1,stack2,13); 
Push(stack1,stack2,17);
Push(stack1,stack2,5);
Display(stack1,stack2);

int min_elem1 = FindMin(stack2);
cout<<"Min element in the list is: "<<min_elem1<<endl<<endl;

int deletedelem2 = Pop(stack1,stack2);
cout<<"Pop element from the stack:"<< deletedelem2 <<endl<<endl;
Display(stack1,stack2);

cout<<endl<<endl;

Push(stack1,stack2,19);
Push(stack1,stack2,8);
Display(stack1,stack2);

cout<<endl<<endl;

int deletedelem1 = Pop(stack1,stack2);
cout<<"Pop element from the stack:"<< deletedelem1 <<endl<<endl;
Display(stack1,stack2);

int min_elem2 = FindMin(stack2);
cout<<"Min element in the list is: "<<min_elem2<<endl<<endl;

return 0;

}

Shyam Raja