If I want to find a minimum element in a stack (integer key), in constant time then it can be done as following:
arr = [ 10, 7, 15, 12, 5 ] 
min_stack = []
main_stack = []
def get_min():
    if len(min_stack) < 1:
        return None
    return min_stack[-1]
def push(key):
    main_stack.append(key)
    if len(min_stack) < 1 or min_stack[-1] > key:
        min_stack.append(key)
def pop():
    key = main_stack.pop()
    min = get_min()
    if key == min:
        min_stack.pop()
    return key
for key in arr:
    push(key)    
In the above solution it is possible to find out min value element in O(1) but it uses an auxiliary memory of size n.
Is there a way that It can be done without using a n size memory or say constant memory, by exploiting arithmetical properties of the integer key.
You can do it in O(1) without O(n) memory if you only want to store a single min value of all the pushed elements. 
If you want to store a history of min elements, then there is no other way but to use a auxiliary data structure to hold them. In that case, using the stack is optimal since you can push/pop in O(1) time, which is the method you are using.
Aside: your code contains a tiny bug:
With your array arr = [2, 2]
 after 2 pushes, min_stack = [2]
When you pop the first time, min_stack = []
                      and main_stack = [2]
 So get_min() will return None, not 2.
To fix it, change push_key:
 if len(min_stack) < 1 or min_stack[-1] >= key:
                        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