I was asked this in an interview:
Design a data structure that allows all these operations in constant, O(1)
, time:
[1, 22, 44, 56, 99, 98, 56]
is 98
.I designed this using a customized stack with two variables, max
and min
, but this doesn't work after Pop'ing a min or max element.
What I tried :
I used a stack with two extra variable max and min:
DS
{
top, //Top of the Stack
min, //Min till now
max //Max till now
}
Push(DS, elem)
Push_Stack(DS.top, elem)
if elem < DS.min
DS.min = elem
if elem > DS.max
DS.max = elem
Range(DS)
return DS.max - DS.min
Pop(DS)
x = Pop_Stack(DS.top)
if (x == DS.min)
DS.min = Find_New_Min(DS.top) //This takes linear time using this approach
if (x == DS.max)
DS.max = Find_New_Max(DS.top)
For all the standard stack operations (push, pop, isEmpty, size), the worst-case run-time complexity can be O(1).
Time Complexities of operations on the stack: push(), pop(), isEmpty() and peek() all take O(1) time. We do not run any loop in any of these operations.
Popping an element from a stack will take O(1) time complexity. Popping the last element in a stack will take O(n).
Time Complexity: O (1) – push () calls push_back () from std::deque, which is a constant time operation. Hence, push () is also a constant time operation. pop () – Removes the top element. pop () removes the top element from the stack, reducing its size by one.
push () and pop () in Stack – C++ STL The Stack is a container of elements with three principal operations: push, which adds an element to the stack. pop, which removes the most recent inserted element from the stack, if there is any.
Push constants are written in ranges. A important reason for that, is that you can have different push constants, at different ranges, in different stages. For example, you can reserve 64 bytes (1 glm::mat4) size on the vertex shader, and then start the pixel shader push constant from offset 64.
Hence, push () is also a constant time operation. pop () – Removes the top element. pop () removes the top element from the stack, reducing its size by one. If there is any second element in the stack, then it becomes the top element after the pop () is being called.
Implement a "Stack" that includes a range function and uses three stacks internally.
The First internal stack will represent the 'real' stack of things being pushed and popped.
The second internal stack will only be pushed to if the new element is bigger than or equal to what is on top of it.
The third internal stack will only be pushed to if the new element is smaller than or equal to what is on top of it.
Now, whenever you need to calculate the range, just peek at the top of the second and third stacks and do some simple math.
Whenever an element needs to be popped off the 'real' stack, check to see if the element is also at the top of each of the other two stacks, if it is, pop it off those stacks as well.
Since you have to pop items off the main stack in the opposite order they came in, you won't ever miss anything in the two other stacks... meaning the top of the second and third internal stacks will always be the max and min.
This is similar to Bryon Lo answer, but before he posted I commented same
Maintain 3 stacks
Rest is self explanatory
push(T value)
{
if (value <= min())
{
s2.push(value);
}
if(value >= max())
{
s3.push(value);
}
s1.push(value);
}
T pop()
{
T value = s1.pop();
if (value == min())
{
s2.pop();
}
return value;
}
T min()
{
if (s2.isEmpty())
{
return MAX_VALUE;
}
else {
return s2.peek();
}
}
T max()
{
if (s3.isEmpty())
{
return MIN_VALUE;
}
else
{
return s3.peek();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With