题目
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
最小栈
使用两个栈,一个栈用来正常放入元素。另一个栈用来,存储每一时刻的最小值
class MinStack {
// 定义两个栈,一个存储普通的元素。一个用来作为同步的最小栈,即同步栈中的每一层存储的都是该情况下的最小元素。
Stack<Integer> stack = new Stack<Integer>();
Stack<Integer> minStack = new Stack<Integer>();
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
// 元素推入栈中
stack.push(x);
if(minStack.isEmpty()){
minStack.push(x);
}else{
minStack.push(Math.min(minStack.peek(), x));
}
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return minStack.peek();
}
}
新奇:这题可以自建链表结构做!!!
自定义链表的用处真的太有意思了。之前对于链表的定义都只是局限在单链表领域,即链表中的一个节点存储一个值,和一个指向下一个节点的Node变量
class Node{
int val;
Node next;
public Node(int val){
this.val = val;
}
}
但是最近接触到的几道题目,都说明了链表的结构非常多样!
像我们平常接触到的二叉树,N叉树,双向链表等等。都是非常经典的链表的运用。
至于为什么:计算机的底层只有两种存储方式(顺序存储、链式存储)。所以一般我们常用的数据结构,都是建立在这之上的逻辑层面的抽象,所以链表的作用千万不要小瞧。
思路如下:使用链表
- 每个链节点,都维护了一个该节点的时候最小值,和本身的值
- 初始化的时候,初始化链表的 head头节点
- 入栈的时候,贴到 head的后面(head.next),并和之前的那个节点的最小值比较,更新最小值
- 弹出元素的时候,将链表的第一个弹出即可
class MinStack {
// 定义一个节点,节点中维护了两个值,一个当前时刻的最小值。一个当前节点的值
private class Node{
int val;
int min;
Node next;
public Node(int val, int min){
this.val = val;
this.min = min;
}
}
private Node head;
public MinStack() {
head = new Node(0,0);
}
public void push(int x) {
if(head.next == null){
head.next = new Node(x, x);
}else{
// 取出原来head.next的最小值
int min = head.next.min;
// 更新最小值
min = Math.min(min, x);
// 创建新节点,并插入到链表的后面
Node node = new Node(x, min);
node.next = head.next;
head.next = node;
}
}
public void pop() {
if(head.next != null)
head.next = head.next.next;
}
public int top() {
if(head.next == null){
return -1;
}
// 如果栈中不为空,去头节点后面一个
return head.next.val;
}
public int min() {
// 由于节点中维护了一个最小元素,所以直接返回 头节点下一个即可
return head.next.min;
}
}
最后一个链表参考自:宝石