剑指Offer(Java版):包含min函数的栈
2016-07-22 00:00
225 查看
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min,push及pop的时间复杂度都是O(1).
看到这个问题,我们的第一反应可能是每次压入一个新元素进栈时,将栈里的所有元素排序,让最小的元素位于栈顶,这样就能在O(1)时间得到最小元素了。但这种思路不能保证最后压入的元素能够最先出栈,因此这个数据结构已经不是栈了。
我们接着想到在栈里添加一个成员变量存放最小的元素。每次压入一个新元素进栈的时候,如果该元素比当前最小的元素还要小,则更新最小元素。面试官听到这种思路之后就会问:如果当前最小的元素被弹出栈了,如何得到下一个最小的元素呢?
分析到这里我们发现仅仅添加一个成员变量存放最小元素是不够的,也就是说当最小元素弹出栈的时候,我们希望能够得到次小元素。因此在压入这个最小元素之前,我们要把次小元素保存起来。因此,在压入这个最小元素之前,我们要把次小元素保存起来。
是不是可以把每次的最小元素都保存起来,放在另外一个辅助栈里呢?我们不妨举几个例子来分析一下把元素压入或者弹出栈的过程。
题关键在于用辅助栈储存什么值。要保证辅助栈的top是最小值,pop之后的顶部仍然是最小值。也就是说辅助栈从上到下存储的应该是最小值->次小值->次次小值……
这里容易进入一个误区就是:难道辅助栈就是对数据栈的排序?如果真是这样,push的时候因为要排序不能满足O(1);数据栈pop的时候,辅助栈要先查找数据栈pop出去的值然后再pop,也不满足O(1)。
当两个栈为空时,push进去的第一个值即为最小值;
push第二个元素时,若push的值<辅助栈顶元素(此处即第一个值),则将此值压进辅助栈;若push的值大于等于辅助栈顶元素,则将辅助栈顶元素再次push进去。
pop的时候,数据栈辅助栈均弹出顶元素。
实现代码如下:
package cglib;
import java.util.Stack;
public class DeleteNode {
Stack<Integer> stack1 = new Stack<Integer>(); // 数据栈
Stack<Integer> stack2 = new Stack<Integer>(); // 辅助栈 用于返回min值
public void push(int node) {
stack1.push(node);
if (stack2.empty()) {
stack2.push(node);
} else {
if (node < stack2.peek().intValue())//如果进入的数小于辅助栈的栈顶元素
stack2.push(node);//则放进去进入的数
else stack2.push(stack2.peek());//否则放进辅助栈的栈顶元素
}
}
@SuppressWarnings("null")
public int pop() {
if(stack1.empty()||stack2.empty()){
return (Integer) null;
}
stack2.pop();
return stack1.pop();
}
public int top() {
if (!stack1.empty())
return stack1.peek().intValue();
else return 0;
}
public int min() {
if (!stack2.empty())
return stack2.peek().intValue();
else return 0;
}
public static void main(String[] args) {
DeleteNode ms = new DeleteNode();
ms.push(4);
ms.push(3);
ms.push(1);
ms.push(5);
ms.push(2);//4,3,1,5,2
//System.out.println("pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
}
}
输出:
min:1 pop:2
min:1 pop:5
min:1 pop:1
min:3 pop:3
看到这个问题,我们的第一反应可能是每次压入一个新元素进栈时,将栈里的所有元素排序,让最小的元素位于栈顶,这样就能在O(1)时间得到最小元素了。但这种思路不能保证最后压入的元素能够最先出栈,因此这个数据结构已经不是栈了。
我们接着想到在栈里添加一个成员变量存放最小的元素。每次压入一个新元素进栈的时候,如果该元素比当前最小的元素还要小,则更新最小元素。面试官听到这种思路之后就会问:如果当前最小的元素被弹出栈了,如何得到下一个最小的元素呢?
分析到这里我们发现仅仅添加一个成员变量存放最小元素是不够的,也就是说当最小元素弹出栈的时候,我们希望能够得到次小元素。因此在压入这个最小元素之前,我们要把次小元素保存起来。因此,在压入这个最小元素之前,我们要把次小元素保存起来。
是不是可以把每次的最小元素都保存起来,放在另外一个辅助栈里呢?我们不妨举几个例子来分析一下把元素压入或者弹出栈的过程。
题关键在于用辅助栈储存什么值。要保证辅助栈的top是最小值,pop之后的顶部仍然是最小值。也就是说辅助栈从上到下存储的应该是最小值->次小值->次次小值……
这里容易进入一个误区就是:难道辅助栈就是对数据栈的排序?如果真是这样,push的时候因为要排序不能满足O(1);数据栈pop的时候,辅助栈要先查找数据栈pop出去的值然后再pop,也不满足O(1)。
当两个栈为空时,push进去的第一个值即为最小值;
push第二个元素时,若push的值<辅助栈顶元素(此处即第一个值),则将此值压进辅助栈;若push的值大于等于辅助栈顶元素,则将辅助栈顶元素再次push进去。
pop的时候,数据栈辅助栈均弹出顶元素。
实现代码如下:
package cglib;
import java.util.Stack;
public class DeleteNode {
Stack<Integer> stack1 = new Stack<Integer>(); // 数据栈
Stack<Integer> stack2 = new Stack<Integer>(); // 辅助栈 用于返回min值
public void push(int node) {
stack1.push(node);
if (stack2.empty()) {
stack2.push(node);
} else {
if (node < stack2.peek().intValue())//如果进入的数小于辅助栈的栈顶元素
stack2.push(node);//则放进去进入的数
else stack2.push(stack2.peek());//否则放进辅助栈的栈顶元素
}
}
@SuppressWarnings("null")
public int pop() {
if(stack1.empty()||stack2.empty()){
return (Integer) null;
}
stack2.pop();
return stack1.pop();
}
public int top() {
if (!stack1.empty())
return stack1.peek().intValue();
else return 0;
}
public int min() {
if (!stack2.empty())
return stack2.peek().intValue();
else return 0;
}
public static void main(String[] args) {
DeleteNode ms = new DeleteNode();
ms.push(4);
ms.push(3);
ms.push(1);
ms.push(5);
ms.push(2);//4,3,1,5,2
//System.out.println("pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
System.out.println("min:" + ms.min() + " pop:" +ms.pop() );
}
}
输出:
min:1 pop:2
min:1 pop:5
min:1 pop:1
min:3 pop:3
相关文章推荐
- 剑指Offer(Java版):栈的压入、弹出序列
- 剑指Offer(Java版):从上往下打印二叉树
- Eclipse去除js(JavaScript)验证错误
- 网站发布后bootstrap字体图标不显示的解决方法
- bootstrap validator 使用示例
- thymeleaf中js 取值
- zepto.min.js和 jquery.js冲突
- 全局异常处理器&上传图片&json格式& restfull&拦截器
- 原生JS相关
- JQuery
- HTML--如何在一张网页添加多张HTML页面
- 41个Web开发者必须收藏的JavaScript实用技巧
- caffe利用caffenet训练自己的图片数据
- JavaScript数组去重的四种方法
- css层叠性规则
- CSS之定位、居中、浮动及利用浮动设计网页布局和导航
- JavaScript 框架设计
- JavaScript—40个Web开发者必须收藏的JavaScript实用技巧
- JSP定义和四大范围
- webpack 学习笔记