JAVA写同步栈_【LeetCode】115.最小栈(辅助栈,java实现)

题目

03a2be41f2edeac7eeaa162c4b95fbed.png

解答

这道题的思想很简单:“以空间换时间”,使用辅助栈是常见的做法。

思路分析:

在代码实现的时候有两种方式:

1、辅助栈和数据栈同步

特点:编码简单,不用考虑一些边界情况,就有一点不好:辅助栈可能会存一些“不必要”的元素。

2、辅助栈和数据栈不同步

特点:由“辅助栈和数据栈同步”的思想,我们知道,当数据栈进来的数越来越大的时候,我们要在辅助栈顶放置和当前辅助栈顶一样的元素,这样做有点“浪费”。基于这一点,我们做一些“优化”,但是在编码上就要注意一些边界条件。

(1)辅助栈为空的时候,必须放入新进来的数;

(2)新来的数小于或者等于辅助栈栈顶元素的时候,才放入,特别注意这里“等于”要考虑进去,因为出栈的时候,连续的、相等的并且是最小值的元素要同步出栈;

(3)出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈。

总结一下:出栈时,最小值出栈才同步;入栈时,最小值入栈才同步。

对比:个人觉得“同步栈”的方式更好一些,因为思路清楚,因为所有操作都同步进行,所以调试代码、定位问题也简单。“不同步栈”,虽然减少了一些空间,但是在“出栈”、“入栈”的时候还要做判断,也有性能上的消耗。

方法一:辅助栈和数据栈同步

参考代码 1:

import java.util.Stack;

public class MinStack {

// 数据栈

private Stack data;

// 辅助栈

private Stack helper;

/**

* initialize your data structure here.

*/

public MinStack() {

data = new Stack<>();

helper = new Stack<>();

}

// 思路 1:数据栈和辅助栈在任何时候都同步

public void push(int x) {

// 数据栈和辅助栈一定会增加元素

data.add(x);

if (helper.isEmpty() || helper.peek() >= x) {

helper.add(x);

} else {

helper.add(helper.peek());

}

}

public void pop() {

// 两个栈都得 pop

if (!data.isEmpty()) {

helper.pop();

data.pop();

}

}

public int top() {

if(!data.isEmpty()){

return data.peek();

}

throw new RuntimeException("栈中元素为空,此操作非法");

}

public int getMin() {

if(!helper.isEmpty()){

return helper.peek();

}

throw new RuntimeException("栈中元素为空,此操作非法");

}

}

复杂度分析:

时间复杂度:O(1),“出栈”、“入栈”、“查看栈顶元素”的操作不论数据规模多大,都只是有限个步骤,因此时间复杂度是:O(1)O(1)。

空间复杂度:O(N),这里 N 是读出的数据的个数。

方法二:辅助栈和数据栈不同步

借用一个辅助栈min_stack,用于存获取stack中最小值。

算法流程:

push()方法: 每当push()新值进来时,如果 小于等于 min_stack栈顶值,则一起push()到min_stack,即更新了栈顶最小值;

pop()方法: 判断将pop()出去的元素值是否是min_stack栈顶元素值(即最小值),如果是则将min_stack栈顶元素一起pop(),这样可以保证min_stack栈顶元素始终是stack中的最小值。

getMin()方法: 返回min_stack栈顶即可。

min_stack作用分析:

min_stack等价于遍历stack所有元素,把升序的数字都删除掉,留下一个从栈底到栈顶降序的栈。

相当于给stack中的降序元素做了标记,每当pop()这些降序元素,min_stack会将相应的栈顶元素pop()出去,保证其栈顶元素始终是stack中的最小元素。

1a43dd26266355a77a7f8380fcd64e0b.gif

参考代码 2:

import java.util.Stack;

public class MinStack {

// 数据栈

private Stack data;

// 辅助栈

private Stack helper;

/**

* initialize your data structure here.

*/

public MinStack() {

data = new Stack<>();

helper = new Stack<>();

}

// 思路 2:辅助栈和数据栈不同步

// 关键 1:辅助栈的元素空的时候,必须放入新进来的数

// 关键 2:新来的数小于或者等于辅助栈栈顶元素的时候,才放入(特别注意这里等于要考虑进去)

// 关键 3:出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈,即"出栈保持同步"就可以了

public void push(int x) {

// 辅助栈在必要的时候才增加

data.add(x);

// 关键 1 和 关键 2

if (helper.isEmpty() || helper.peek() >= x) {

helper.add(x);

}

}

public void pop() {

// 关键 3:data 一定得 pop()

if (!data.isEmpty()) {

// 注意:声明成 int 类型,这里完成了自动拆箱,从 Integer 转成了 int,因此下面的比较可以使用 "==" 运算符

// 参考资料:https://www.cnblogs.com/GuoYaxiang/p/6931264.html

// 如果把 top 变量声明成 Integer 类型,下面的比较就得使用 equals 方法

int top = data.pop();

if(top == helper.peek()){

helper.pop();

}

}

}

public int top() {

if(!data.isEmpty()){

return data.peek();

}

throw new RuntimeException("栈中元素为空,此操作非法");

}

public int getMin() {

if(!helper.isEmpty()){

return helper.peek();

}

throw new RuntimeException("栈中元素为空,此操作非法");

}

}

参考代码3:

class MinStack {

private Stack stack;

private Stack min_stack;

public MinStack() {

stack = new Stack<>();

min_stack = new Stack<>();

}

public void push(int x) {

stack.push(x);

if(min_stack.isEmpty() || x <= min_stack.peek())

min_stack.push(x);

}

public void pop() {

if(stack.pop().equals(min_stack.peek()))

min_stack.pop();

}

public int top() {

return stack.peek();

}

public int getMin() {

return min_stack.peek();

}

}

复杂度分析:

时间复杂度:O(1),“出栈”、“入栈”、“查看栈顶元素”的操作不论数据规模多大,都只有有限个步骤,因此时间复杂度是:O(1)。

空间复杂度:O(N),这里 N是读出的数据的个数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值