zoukankan      html  css  js  c++  java
  • Min Stack

    Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

    • push(x) -- Push element x onto stack.
    • pop() -- Removes the element on top of the stack.
    • top() -- Get the top element.
    • getMin() -- Retrieve the minimum element in the stack.

    Example:

    MinStack minStack = new MinStack();
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    minStack.getMin();   --> Returns -3.
    minStack.pop();
    minStack.top();      --> Returns 0.
    minStack.getMin();   --> Returns -2.

    这是一道有意思的设计题。最小栈其余都和普通栈类似,但是最后一个要求:在常数时间内返回stack的最小值需要特别的处理。

    拿到这道题我的第一思路是在栈的倒数第二位存储最小值,但是发现后续弹出和更新都很麻烦,遂放弃,但是这种解法其实可以再辅以最小值做一个改进实现。

    目前比较主流的思路是,除了本身的stack以外,再维护一个保存最小值的stack:trackMin。当x<=trackMin[-1]时,执行trackMin.append(x)。以记录新的最小值。但是注意等于的情况下也要执行append,不然有重复最小元素相继入栈,又相继弹出时,弹出前面的元素时,trackMin的栈顶存的不再是最小元素:

    例如压入以下数后:
    xi:    3 2 1 2 1 
    trackMin: 3 2 1

    此时如果pop,则变为
    xi:    3 2 1 2
    trackMin: 3 2

    然而实际栈里的最小值仍旧为1,这个1因为重复数字的关系在trackMin中丢失。代码如下:
    class MinStack(object):
    
        def __init__(self):
            """
            initialize your data structure here.
            """
            self.stack = []
            self.trackMin = []
            
    
        def push(self, x):
            """
            :type x: int
            :rtype: void
            """
            if not self.trackMin or self.trackMin[-1]>=x:
                self.trackMin.append(x)
            self.stack.append(x)
            return
            
            
    
        def pop(self):
            """
            :rtype: void
            """
            if len(self.stack) == 0:
                return 
            if self.stack.pop()==self.trackMin[-1]:
                self.trackMin.pop()
            
    
        def top(self):
            """
            :rtype: int
            """
            if self.stack:
               return self.stack[-1]
            else:
               return None
            
    
        def getMin(self):
            """
            :rtype: int
            """
            if self.trackMin:
                return self.trackMin[-1]
            else:
                return None
            
    
    
    # Your MinStack object will be instantiated and called as such:
    # obj = MinStack()
    # obj.push(x)
    # obj.pop()
    # param_3 = obj.top()
    # param_4 = obj.getMin()

    除了使用两个栈的思路,使用一个栈也是可以实现的,而且有多种思路:一个是使用一个栈,但是栈中存的是,值和压入该值时栈内的最小值这个键值对,或者tuple。显然这种空间复杂度是2(n)比上面双栈在平均情况下,内存消耗要大。这种解法的Java实现如下:

    class MinStack
    {
        static class Element
        {
            final int value;
            final int min;
            Element(final int value, final int min)
            {
                this.value = value;
                this.min = min;
            }
        }
        final Stack<Element> stack = new Stack<>();
    
        public void push(int x) {
            final int min = (stack.empty()) ? x : Math.min(stack.peek().min, x);
            stack.push(new Element(x, min));
        }
    
        public void pop()
        {
            stack.pop();
        }
    
        public int top()
        {
            return stack.peek().value;
        }
    
        public int getMin()
        {
            return stack.peek().min;
        }
    }

    另外一种解法是维护一个最小值min,每个进栈的元素在栈中存储的实际是和min的gap值,但是这种解法存在overflow的可能,运算也比较大,Java代码实现如下:

    public class MinStack {
        long min;
        Stack<Long> stack;
    
        public MinStack(){
            stack=new Stack<>();
        }
    
        public void push(int x) {
            if (stack.isEmpty()){
                stack.push(0L);
                min=x;
            }else{
                stack.push(x-min);//Could be negative if min value needs to change
                if (x<min) min=x;
            }
        }
    
        public void pop() {
            if (stack.isEmpty()) return;
    
            long pop=stack.pop();
    
            if (pop<0)  min=min-pop;//If negative, increase the min value
    
        }
    
        public int top() {
            long top=stack.peek();
            if (top>0){
                return (int)(top+min);
            }else{
               return (int)(min);
            }
        }
    
        public int getMin() {
            return (int)min;
        }
    }

    最后一种只用一个stack的解法,就是基于我所说的倒数第二个元素存储最小值的改进,这里最小值改进为用单独的min来存储,如果最小值被更新,则把该最小值压栈,具体见Java代码:

    class MinStack {
        int min=Integer.MAX_VALUE;
        Stack<Integer> stack = new Stack<Integer>();
        public void push(int x) {
           // only push the old minimum value when the current 
           // minimum value changes after pushing the new value x
            if(x <= min){          
                stack.push(min);
                min=x;
            }
            stack.push(x);
        }
    
        public void pop() {
           // if pop operation could result in the changing of the current minimum value, 
           // pop twice and change the current minimum value to the last minimum value.
            if(stack.peek()==min) {
                stack.pop();
                min=stack.peek();
                stack.pop();
            }else{
                stack.pop();
            }
            if(stack.empty()){
                min=Integer.MAX_VALUE;
            }
        }
    
        public int top() {
            return stack.peek();
        }
    
        public int getMin() {
            return min;
        }
    }

    设计题思路五花八门,还是很有意思哒~

  • 相关阅读:
    [Gamma阶段]展示博客
    [Gamma阶段]测试报告
    软工实践个人总结
    小组最终答辩
    第08组 Beta版本演示
    第08组 Beta冲刺(5/5)
    第08组 Beta冲刺(4/5)
    第08组 Beta冲刺(2/5)
    第08组 Beta冲刺(3/5)
    第08组 Beta冲刺(1/5)
  • 原文地址:https://www.cnblogs.com/sherylwang/p/5470096.html
Copyright © 2011-2022 走看看