Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

字节&leetcode155:最小栈(包含getMin函数的栈) #23

Open
sisterAn opened this issue Apr 21, 2020 · 21 comments
Open

字节&leetcode155:最小栈(包含getMin函数的栈) #23

sisterAn opened this issue Apr 21, 2020 · 21 comments

Comments

@sisterAn
Copy link
Owner

sisterAn commented Apr 21, 2020

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) —— 将元素 x 推入栈中。
  • pop() —— 删除栈顶的元素。
  • top() —— 获取栈顶元素。
  • getMin() —— 检索栈中的最小元素。

示例:

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

附leetcode地址:leetcode

@chenzesam
Copy link

chenzesam commented Apr 22, 2020

class MinStack {
  constructor () {
    this.length = 0;
    this.content = [];
    this.mins = [];
  }
  push (val) {
    const curMin = this.mins[this.length - 1] !== undefined ? this.mins[this.length - 1] : Infinity;
    this.content[this.length++] = val;
    this.mins[this.length - 1] = Math.min(curMin, val);
  }
  pop () {
    return this.content[--this.length]
  }
  top () {
    return this.content[this.length - 1]
  }
  getMin () {
    return this.mins[this.length - 1];
  }
}

@13001920223
Copy link

var MinStack = function() {
  this.stack = [];
  this.min = Number.MAX_SAFE_INTEGER;
};


MinStack.prototype.push = function(x) {
  if(this.min >= x){
      this.stack.push(x);
      this.min = x;
  } else {
    this.stack.push(x)
  }
};

MinStack.prototype.pop = function() {
  const min = this.stack.pop()
  if(min == this.min){
    this.min = Math.min(...this.stack)
  }
};

MinStack.prototype.top = function() {
  return this.stack[this.stack.length-1];
};

MinStack.prototype.getMin = function() {
  return this.min;
};

@sisterAn
Copy link
Owner Author

在常数时间内检索到最小元素的栈,即仅需保证 getMin 的时间复杂度为 O(1) 即可

var MinStack = function() {
    this.items = []
    this.min = null
};

// 进栈
MinStack.prototype.push = function(x) {
    if(!this.items.length) this.min = x 
    this.min = Math.min(x, this.min)
    this.items.push(x) 
};

// 出栈
MinStack.prototype.pop = function() {
    let num = this.items.pop() 
    this.min = Math.min(...this.items)
    return num
};

// 获取栈顶元素
MinStack.prototype.top = function() {
    if(!this.items.length) return null
    return this.items[this.items.length -1] 
};

// 检索栈中的最小元素
MinStack.prototype.getMin = function() {
    return this.min
};

时间复杂度:进栈O(1),出栈O(n),获取栈顶元素O(1),获取最小元素O(1)

空间复杂度:O(n)

leetcode

@XGHeaven
Copy link

随便看了下 😂
@chenzesam 你没有考虑 push(0) 的情况。
@sisterAn 出栈也可以做到 O(1) 的,空间复杂度不变,见上面的那个老哥
如果 n 很大而且空间要求很严格的话,可以启用 mins 数组的压缩,不过感觉得不偿失

@chenzesam
Copy link

@XGHeaven 可以举个 test case 吗?

@Mr-jili
Copy link

Mr-jili commented Apr 23, 2020

@chenzesam pop感觉不好使吧,只是改变length,但数组没有去除

@chenzesam
Copy link

@Mr-jili 只是将栈的功能实现了, 不然使用数组的 pop 和 push, 那就不需要实现栈了. length 只是用来划的

@XGHeaven
Copy link

@chenzesam 直接实例化之后跑这个
image

@zhangxiaos
Copy link

zhangxiaos commented Apr 27, 2020

class MinStack {
    constructor() {
      this.min = undefined // 存放最小值
      this.secondMin = undefined // 存放第二小值
      this.stack = []
    }
    push(item) {
      this.stack.push(item)
      if (this.min === undefined) {
        this.min = item
      }
      if (item < this.min) {
        this.secondMin = this.min
        this.min = item
      }
    }
    pop() {
      const popItem = this.stack.pop()
      if (popItem === this.min) {
        this.min = this.secondMin
      }
      return popItem
    }
    top() {
      if (!this.stack.length) return null
      return this.stack[this.stack.length - 1]
    }
    getMin() {
      if (!this.stack.length) return null
      console.log('min:', this.min)
      return this.min
    }
  }

  const minStack = new MinStack();
  minStack.push(-2);
  minStack.push(0);
  minStack.push(-3);
  minStack.getMin();   // --> 返回 -3.
  minStack.pop();
  minStack.top();      // --> 返回 0.
  minStack.getMin();   // --> 返回 -2.

@zero9527
Copy link

@chenzesam 直接实例化之后跑这个
image

push 没有return 一个返回值,就相当于return undefined

@zhangxuyang950313
Copy link

zhangxuyang950313 commented Jun 3, 2020

function MinStack() {
  let list = [];
  let min = null;
  this.push = val => {
    if (typeof val === 'number' && !Number.isNaN(val)) {
      list.push(val);
      min = min === null ? val : Math.min(min, val);
    } else if (Array.isArray(val)) {
      list.push(...val);
      min = min === null ? Math.min(...val) : Math.min(...[min, ...val]);
    }
    return list.length;
  };
  this.pop = () => {
    const last = list.pop();
    if (last === min) {
      min = Math.min(...list);
    }
    return last;
  };
  this.top = () => {
    return list[list.length - 1];
  };
  this.getMin = () => {
    return min;
  };
}

@VivenZZ
Copy link

VivenZZ commented Aug 8, 2020

关键点应该是常数时间内找到最小值,我就将最小值定义一个变量。
在添加和移除元素的时候 都会重置最小值

function MinStack() {
  let items = []
  let min
  this.push = function(item) {
    min = min && item > min ? min : item
    return items.push(item)
  }
  this.pop = function(){
    let item = items.pop()
    min = item > min ? min : Math.min(...items)
    return item
  }
  this.getMin = function() {
    return min
  }
  this.top = function(){
    return items[items.length - 1 ] 
  }
}

@qianlongo
Copy link

var MinStack = function() {
  this.stack = []
  this.minStack = []
};

/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
  this.stack.push(x)

  if (!this.minStack.length || x <= this.minStack[ this.minStack.length - 1 ]) {
    this.minStack.push(x)
  }
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
  const delEle = this.stack.pop()

  if (delEle === this.minStack[ this.minStack.length - 1 ]) {
    this.minStack.pop()
  }
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
  return this.stack[ this.stack.length - 1 ]
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function() {
  return this.minStack[ this.minStack.length - 1 ]
};

@webpig
Copy link

webpig commented Oct 9, 2020

// 用两个栈,一个用于存储所有原始数据,一个用于存储每组数据的最小值
/**
 * initialize your data structure here.
 */
var MinStack = function() {
  this.stack = []
  this.minStack = [Infinity]
};

/**
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
  this.stack.push(x)
  const minVal = Math.min(this.minStack[this.minStack.length - 1], x)
  this.minStack.push(minVal)
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
  this.stack.pop()
  this.minStack.pop()
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
  return this.stack[this.stack.length - 1]
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function() {
  return this.minStack[this.minStack.length - 1]
};

@109km
Copy link

109km commented Dec 1, 2020

class MinStack {
  constructor() {
    this.min = Infinity;
    // Each element is also an array [currentValue,currentMin]
    this.elements = [];
  }
  get top() {
    return this.elements[this.size - 1][0];
  }
  get size() {
    return this.elements.length;
  }
  push(el) {
    if (this.min > el) {
      this.min = el;
      this.elements.push([el, el]);
    } else {
      this.elements.push([el, this.min]);
    }
  }
  pop() {
    const el = this.elements.pop();
    return el[0];
  }
  getMin() {
    return this.elements[this.size - 1][1];
  }
}

@azl397985856
Copy link

题目地址(155. 最小栈)

https://leetcode-cn.com/problems/min-stack/

题目描述

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
 

示例:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.
 

提示:

pop、top 和 getMin 操作总是在 非空栈 上调用。

前置知识

公司

  • amazon
  • bloomberg
  • google
  • snapchat
  • uber
  • zenefits
  • 阿里
  • 腾讯
  • 百度
  • 字节

两个栈

思路

我们使用两个栈:

  • 一个栈存放全部的元素,push,pop都是正常操作这个正常栈。
  • 另一个存放最小栈。 每次push,如果比最小栈的栈顶还小,我们就push进最小栈,否则不操作
  • 每次pop的时候,我们都判断其是否和最小栈栈顶元素相同,如果相同,那么我们pop掉最小栈的栈顶元素即可

关键点

  • 往minstack中 push的判断条件。 应该是stack为空或者x小于等于minstack栈顶元素

代码

  • 语言支持:JS,C++,Java,Python

JavaScript Code:

/**
 * initialize your data structure here.
 */
var MinStack = function() {
    this.stack = []
    this.minStack = []
};

/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
    this.stack.push(x)
    if (this.minStack.length == 0 ||  x <= this.minStack[this.minStack.length - 1]) {
        this.minStack.push(x)
    }
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    const x = this.stack.pop()
    if (x !== void 0 &&  x === this.minStack[this.minStack.length - 1]) {
        this.minStack.pop()
    }
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    return this.stack[this.stack.length - 1]
};

/**
 * @return {number}
 */
MinStack.prototype.min = function() {
    return this.minStack[this.minStack.length - 1]
};

/** 
 * Your MinStack object will be instantiated and called as such:
 * var obj = new MinStack()
 * obj.push(x)
 * obj.pop()
 * var param_3 = obj.top()
 * var param_4 = obj.min()
 */

C++ Code:

class MinStack {
    stack<int> data;
    stack<int> helper;
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        data.push(x);
        if(helper.empty() || helper.top() >= x)
        {
            helper.push(x);
        }
        
    }
    
    void pop() {
        int top = data.top();
        data.pop();
        if(top == helper.top())
        {
            helper.pop();
        }
        
    }
    
    int top() {
        return data.top();
    }
    
    int getMin() {
        return helper.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

Java Code:

public class MinStack {

    // 数据栈
    private Stack<Integer> data;
    // 辅助栈
    private Stack<Integer> helper;

    /**
     * initialize your data structure here.
     */
    public MinStack() {
        data = new Stack<>();
        helper = new Stack<>();
    }
    
    public void push(int x) {
        // 辅助栈在必要的时候才增加
        data.add(x);
        if (helper.isEmpty() || helper.peek() >= x) {
            helper.add(x);
        }
    }

    public void pop() {
        // 关键 3:data 一定得 pop()
        if (!data.isEmpty()) {
            // 注意:声明成 int 类型,这里完成了自动拆箱,从 Integer 转成了 int,
            // 因此下面的比较可以使用 "==" 运算符
            int top = data.pop();
            if(top == helper.peek()){
                helper.pop();
            }
        }
    }

    public int top() {
        if(!data.isEmpty()){
            return data.peek();
        }
    }

    public int getMin() {
        if(!helper.isEmpty()){
            return helper.peek();
        }
    }
}

Python3 Code:

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.minstack = []

    def push(self, x: int) -> None:
        self.stack.append(x)
        if not self.minstack or x <= self.minstack[-1]:
            self.minstack.append(x)

    def pop(self) -> None:
        tmp = self.stack.pop()
        if tmp == self.minstack[-1]:
            self.minstack.pop()

    def top(self) -> int:
        return self.stack[-1]

    def min(self) -> int:
        return self.minstack[-1]


# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()

复杂度分析

  • 时间复杂度:O(1)
  • 空间复杂度:O(1)

一个栈

思路

符合直觉的方法是,每次对栈进行修改操作(push和pop)的时候更新最小值。 然后getMin只需要返回我们计算的最小值即可,
top也是直接返回栈顶元素即可。 这种做法每次修改栈都需要更新最小值,因此时间复杂度是O(n).

是否有更高效的算法呢?答案是有的。

我们每次入栈的时候,保存的不再是真正的数字,而是它与当前最小值的差(当前元素没有入栈的时候的最小值)。
这样我们pop和top的时候拿到栈顶元素再加上上一个最小值即可。
另外我们在push和pop的时候去更新min,这样getMin的时候就简单了,直接返回min。

注意上面加粗的“上一个”,不是“当前的最小值”

经过上面的分析,问题的关键转化为“如何求得上一个最小值”,解决这个的关键点在于利用min。

pop或者top的时候:

  • 如果栈顶元素小于0,说明栈顶是当前最小的元素,它出栈会对min造成影响,我们需要去更新min。
    上一个最小的是“min - 栈顶元素”,我们需要将上一个最小值更新为当前的最小值

因为栈顶元素入栈的时候的通过 栈顶元素 = 真实值 - 上一个最小的元素 得到的,
而真实值 = min, 因此可以得出上一个最小的元素 = 真实值 -栈顶元素

  • 如果栈顶元素大于0,说明它对最小值没有影响,上一个最小值就是上上个最小值。


关键点

  • 最小栈存储的不应该是真实值,而是真实值和min的差值
  • top的时候涉及到对数据的还原,这里千万注意是上一个最小值

代码

  • 语言支持:JS,C++,Java,Python

Javascript Code:

/*
 * @lc app=leetcode id=155 lang=javascript
 *
 * [155] Min Stack
 */
/**
 * initialize your data structure here.
 */
var MinStack = function() {
  this.stack = [];
  this.minV = Number.MAX_VALUE;
};

/**
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
  // update 'min'
  const minV = this.minV;
  if (x < this.minV) {
    this.minV = x;
  }
  return this.stack.push(x - minV);
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
  const item = this.stack.pop();
  const minV = this.minV;

  if (item < 0) {
    this.minV = minV - item;
    return minV;
  }
  return item + minV;
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
  const item = this.stack[this.stack.length - 1];
  const minV = this.minV;

  if (item < 0) {
    return minV;
  }
  return item + minV;
};

/**
 * @return {number}
 */
MinStack.prototype.min = function() {
  return this.minV;
};

/**
 * Your MinStack object will be instantiated and called as such:
 * var obj = new MinStack()
 * obj.push(x)
 * obj.pop()
 * var param_3 = obj.top()
 * var param_4 = obj.min()
 */

C++ Code:

class MinStack {
    stack<long> data;
    long min = INT_MAX;
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        data.push(x - min);
        if(x < min)
        {
            min = x;
        }
        
    }
    
    void pop() {
        long top = data.top();
        data.pop();
        // 更新最小值
        if(top < 0)
        {
            min -= top;
        }
        
    }
    
    int top() {
        long top = data.top();
        // 最小值为 min
        if (top < 0)
        {
            return min;
        }
        else{
            return min+top;
        }
    }
    
    int getMin() {
        return min;
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

Java Code:

class MinStack {
    long min;
    Stack<Long> stack;
    
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
    }
    
    public void push(int x) {
        if (stack.isEmpty()) {
            stack.push(0L);
            min = x;
        }
        else {
            stack.push(x - min);
            if (x < min)
                min = x;
        }
    }
    
    public void pop() {
        long p = stack.pop();
        
        if (p < 0) {
            // if (p < 0), the popped value is the min
            // Recall p is added by this statement: stack.push(x - min);
            // So, p = x - old_min
            // old_min = x - p
            // again, if (p < 0), x is the min so:
            // old_min = min - p
            min = min - p;
        }
    }
    
    public int top() {
        long p = stack.peek();
        
        if (p < 0) {
            return (int) min;
        }
        else {
            // p = x - min
            // x = p + min
            return (int) (p + min);
        }
    }
    
    public int getMin() {
        return (int) min;    
    }
}

Python Code:

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.minV = float('inf')
        self.stack = []

    def push(self, x: int) -> None:
        self.stack.append(x - self.minV)
        if x < self.minV:
            self.minV = x

    def pop(self) -> None:
        if not self.stack:
            return
        tmp = self.stack.pop()
        if tmp < 0:
            self.minV -= tmp

    def top(self) -> int:
        if not self.stack:
            return
        tmp = self.stack[-1]
        if tmp < 0:
            return self.minV
        else:
            return self.minV + tmp

    def min(self) -> int:
        return self.minV



# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()

复杂度分析

  • 时间复杂度:O(1)
  • 空间复杂度:O(1)

更多题解可以访问我的LeetCode题解仓库:https://github.com/azl397985856/leetcode 。 目前已经40K star啦。

关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。

@JohnApache
Copy link

JohnApache commented Apr 29, 2021

class MinStack {

    private _stack: number[] = []
    private min: number | undefined;

    push (data: number) {
        if (this.min === undefined) {
            this.min = data;
        } else {
            this.min = Math.min(data, this.min);
        }
        this._stack.push(data);
    }

    pop () {
        this._stack.pop();
        if (this._stack.length <= 0) {
            this.min = undefined;
        } else {
            this.min = Math.min(...this._stack);
        }
    }

    top () {
        return this._stack[this._stack.length - 1];
    }

    getMin () {
        return this.min;
    }

}

@lejsure
Copy link

lejsure commented Jan 5, 2022

// if push item is a Array

class MinStack {
      constructor() {
          this.min = null;
          this.stack = [];
      }

    push(item) {
        if (Array.isArray(item)) {
            this.stack.push(...item.flat(Infinity));
            this.min === null ? this.min = Math.min(...item.flat(Infinity)) : this.min = Math.min(...[this.min,...item.flat(Infinity)])
        } else {
            this.stack.push(item)
            this.min === null ? this.min = item : this.min = Math.min(this.min, item)
        }
        
       return this.stack.length;
    }

    pop() {
        const _last = this.stack.length ? this.stack.pop() : null;

        if (this.min === _last) {
            this.min = Math.min(...this.stack);
        }

        return _last;
    }

    top() {
        const _top = this.stack.length ? this.stack[this.stack.length - 1] : null

        return _top;
    }

    getMin() {
        return this.min
    }
}

@RyanMeg123
Copy link

RyanMeg123 commented May 26, 2022

class minStack {
    constructor (){
        this.stack = []
    }

    push (e) {
        this.stack.push(e)
    }

    pop () {
        this.stack.pop()
    }
    top () {
        return this.stack[this.stack.length -1]
    }
    getMin () {
        let sort = [...this.stack].sort((a,b) => a-b)
        return sort[0]
    }
}

@RainyNight9
Copy link

lass MinStack {
    data: number[]
    constructor() {
        this.data = []
    }

    push(val: number): void {
        this.data.push(val)
        return null
    }

    pop(): void {
        this.data.pop()
        return null
    }

    top(): number {
        // let top = this.data.pop()
        // this.data.push(top)
        // return top
        return this.data[this.data.length-1]
    }

    getMin(): number {
        let min = this.data[0]
        for(let i=1;i<this.data.length;i++){
            let item = this.data[i]
            if(item<min) {
                min = item
            }
        }
        return min
    }
}

@AlexZhang11
Copy link

function MinStack(){
    this.stack = []
    this.stack2 = []
}
MinStack.prototype.push = function(val){
    this.stack.push(val)
    if(this.stack2.length==0||this.stack2[this.stack2.length-1]>val){
        this.stack2.push(val)
    }
}
MinStack.prototype.pop = function(){
    if(this.stack.pop()===this.stack2[this.stack2.length-1]){
        this.stack2.pop()
    }
}
MinStack.prototype.top = function(){
    return this.stack[this.stack.length-1]
}
MinStack.prototype.getMin = function(){
    return this.stack2[this.stack2.length-1]
}

let minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();  // 返回 -3.
minStack.pop();
minStack.top();      // 返回 0.
minStack.getMin();   //-2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests