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.

题目分析:

这道题的考察点有两个,一个对栈的理解,另一个是栈的实现。
栈是一种先进先出的数据结构。进来的入口称为栈顶,底部称为栈底,栈的标准操作有:

  • push:从栈顶推入元素
  • pop:移除栈顶的元素
  • peek ( top ):查看栈顶的元素,但是不移除

题目增加 getMin 的操作,返回栈的最小值。

这道题可以用语言提供的栈来写,比如 Java 的 Stack,但其实用普通数组就能实现一个栈。

问题在于:如何维护栈的最小值?

根据大家的思路,我整理了几种

  • 解法一:维护两个栈,一个存当前值 a,另一个辅助栈存 a 对应的最小值 min 。好处是简洁易懂,缺点是空间双倍了。详情看官方题解
  • 解法二:双端队列(链表实现),最小值放前面,当前值放后面,缺点也是用两倍长度了。详情
  • 解法三:用数组来实现一个栈,用来做正常的 push、pop、peek,getMin 的时候遍历数组找到最小值。好处是简洁,不使用额外空间,缺点是 getMin 是 O(n) 的复杂度。详情
  • 解法四:比较巧妙,思路是栈里保存差值。栈不是用来存当前值 a,而是保存 a 和 min 的差值,pop() 时结算一下再返回结果。好处是不使用额外空间,getMin() 是 O(1) 时间复杂度。(面试的时候被问到不能用额外空间)。详情

代码实现:

先展示解法一的代码。建议自己实现栈,不然没锻炼价值了。
新增的数追加在数组末尾,出栈也发生在数组末尾,避免移动元素。

type MinStack struct {
	xStack []int  
	mStack []int // 辅助栈
}

func Constructor() MinStack {
	return MinStack{
		xStack: []int{},
		mStack: []int{math.MaxInt32},
	}
}

func (s *MinStack) Push(val int) {
	s.xStack = append(s.xStack, val)
	// 计算辅助栈
	topMin := s.mStack[len(s.mStack)-1]
	s.mStack = append(s.mStack, min(topMin, val))
}

func (this *MinStack) Pop() {
	this.xStack = this.xStack[:len(this.xStack)-1 ]
	this.mStack = this.mStack[:len(this.mStack)-1 ]
}

func (this *MinStack) Top() int {
	return this.xStack[len(this.xStack)-1 ]

}

func (this *MinStack) GetMin() int {
	return this.mStack[len(this.mStack)-1]
}

func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}

/**
 * Your MinStack object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(val);
 * obj.Pop();
 * param_3 := obj.Top();
 * param_4 := obj.GetMin();
 */

解法四那么巧妙,有必要写写:

class MinStack {

private Stack<Long> stack;
    private int min;

    public MinStack() {
        stack = new Stack<>();
        min = 0;
    }

    public void push(int val) {
        if (stack.isEmpty()) {
            stack.push(0L);
            min = val;
        } else {
            // val是最小值,有可能越界,因此用 long 类型
            stack.push((long) val - min);
            min = Math.min(val, min);
        }
    }

    public void pop() {
        long pop = stack.pop();
        if (pop <= 0) {
            // int res = min;
            min = (int) (min - pop);
            // return res;
        } else {
            // return min + pop;
        }
    }

    public int top() {
        long diff = stack.peek();
        if (diff <= 0) {
            return min;
        } else {
            return (int) (min + diff);
        }
    }

    public int getMin() {
        return min;
    }
}

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

本篇完

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值