原文:
How would you design a stack which, in addition to push and pop, also has a function min which returns the minimum element? Push, pop and min should all operate in O(1) time.
译文:
实现一个栈,除了push和pop操作,还要实现min函数以返回栈中的最小值。 push,pop和min函数的时间复杂度都为O(1)。
方法一:
最直接的想法是使用一个变量,实时记录当前最小值元素所在数组下标,但是存在问题,如果最小值为栈顶元素,则此时出栈之后,下一个
最小值元素所在位置无法得知
可以使用方法,数组元素使用结点,两个元素,一个记录当前元素的值,一个记录以当前元素为栈顶时候的最小值,这样使得如果元素出栈,
则下一个栈顶元素中始终记录下一个最小值,而且元素入栈时候也只需要比较当前入栈元素和之前元素所记录最小值比较,如果小于则记录当前袁术
为栈顶最小值,如果大于,则直接复制之前的最小值,也就是和之前元素的最小值一样。
只是需要牺牲空间,因为每个元素所在结点需要同时记录当前元素,还需要记录以当前元素为栈顶的最小值元素。
package chapter_3_StacksandQueues;
class Node_2 {
public int data;
// 区间当前位置到栈底元素中最小的
// 这样如果当前栈顶最小元素出栈,则下一个元素始终记录当前栈最小元素,并获取时间复杂度最小0(1)
public int preMin;
}
/**
*
* 出栈,入栈,获取栈内最小元素时间复杂度都是0(1)
*
*/
class Stack_2 {
private Node_2 stack[] ;
private int size;
private int top;
public Stack_2(int size) {
stack = new Node_2[size];
this.size = size;
top = -1;
}
public boolean isEmpty() {
return top == -1;
}
public boolean isFull() {
return top == (size-1);
}
public void push(int data) {
if (isFull()) {
System.out.println("Stack if full!");
return;
}
stack[++top] = new Node_2();
stack[top].data = data;
if(top == 0) {
stack[top].preMin = data;
} else {
stack[top].preMin = data < stack[top-1].preMin ? data: stack[top-1].preMin;
}
}
public void pop() {
if (isEmpty()) {
System.out.println("Stack if empty!");
return;
}
top--;
}
public int top() {
if (isEmpty()) {
System.out.println("Stack if empty!");
return -1;
}
return stack[top].data;
}
public int min() {
if (isEmpty()) {
System.out.println("Stack if empty!");
return -1;
}
return stack[top].preMin;
}
}
/**
*
* 实现一个栈,除了push和pop操作,还要实现min函数以返回栈中的最小值。 push,pop和min函数的时间复杂度都为O(1)。
*
*/
public class Question_3_2 {
public static void main(String args[]) {
Stack_2 stack = new Stack_2(15);
int data[] = {1,2,3,10,9,8,7,5,10,100,102,12,-1};
for(int i=0; i<data.length; i++) {
stack.push(data[i]);
System.out.println("Cur Min in Stack is = " + stack.min());
}
stack.pop();
System.out.println("Cur Min in Stack is = " + stack.min());
}
}
方法二:
上述方法需要两倍的空间开销,并且如果存在入栈元素是倒序入栈,1,2,3,4,5,6,7,8,9,10.....则每个结点中记录的当前
位置之前的最小值都是1,因为不管在哪个位置,当前的最小值都是1,则存在严重的数据冗余问题,如何消去这些冗余数据,则可以使用一个链栈来表示最小值情况。最小值链栈始终记录当前情况下的最小值。
如果元素入栈,同时比较当前最小值链栈栈顶元素,如果比栈顶元素小,则说面当前元素为最小值(当前情况下),则入栈最小值栈。
如果大于等于,则无需入栈,栈顶元素还是当前最小值。
如果出栈,则比较当前出栈元素和最小值链栈栈顶元素大小,如果等于栈顶元素,则说明当前元素如果没有出栈,则是最小值,出栈,则不再存在这个元素,自然需要去除最小值的记录,则同时也出栈。不等于,则无需出栈。
package chapter_3_StacksandQueues;
class Node_2_2 {
public int data;
public Node_2_2 pre;
}
/**
*
* 链栈记录非冗余最小值
*
*/
class Stack_Min {
private Node_2_2 top;
public Stack_Min() {
top = null;
}
public boolean isEmpty() {
return top == null;
}
public void push(int data) {
Node_2_2 node = new Node_2_2();
node.data = data;
if(top == null) {
top = node;
top.pre = null;
} else {
node.pre = top;
top = node;
}
}
public int top() {
if(top == null) {
System.out.println("Stack if empty!");
return -1000;
}
return top.data;
}
public void pop() {
if(top == null) {
System.out.println("Stack if empty!");
return;
}
top = top.pre;
}
}
/**
*
* 假设除了用一个栈s1来保存数据,还用另一个栈s2来保存这些非冗余最小值
*
*/
class Stack_2_2 {
private int stack[];
private int top;
private int size;
// 实时栈顶记录当前最小值
// 如果元素入栈,stack_Min判断栈顶元素和入栈元素大小,是当前最小则同时入栈stack_Min
private Stack_Min stack_Min;
public Stack_2_2(int size) {
stack = new int[size];
this.size = size;
top = -1;
stack_Min = new Stack_Min();
}
public boolean isEmpty() {
return top == -1;
}
public boolean isFull() {
return top == (size-1);
}
public void push(int data) {
if(isFull()) {
System.out.println("Stack if full!");
return;
}
stack[++ top] = data;
int minTop = stack_Min.top();
// 判断是否比最小值stack_Min栈顶元素还小
// 如果小玉stack_Min栈顶则当前data为最小,则入栈
if(minTop == -1000 || data < minTop) {
stack_Min.push(data);
}
}
public int top() {
if (isEmpty()) {
System.out.println("Stack if empty!");
return -1000;
}
return stack[top];
}
public void pop() {
if (isEmpty()) {
System.out.println("Stack if empty!");
return;
}
int minTop = stack_Min.top();
if(stack[top] == minTop) {
stack_Min.pop();
}
top--;
}
public int min() {
return stack_Min.top();
}
}
/**
*
* 实现一个栈,除了push和pop操作,还要实现min函数以返回栈中的最小值。 push,pop和min函数的时间复杂度都为O(1)。
*
*/
class Question_3_2_2 {
public static void main(String args[]) {
Stack_2 stack = new Stack_2(15);
int data[] = {10,28,30,15,90,8,7,5,13,1,102,12,-1};
for(int i=0; i<data.length; i++) {
stack.push(data[i]);
System.out.println("Cur Min in Stack is = " + stack.min());
}
System.out.println("pop");
stack.pop();
System.out.println("Cur Min in Stack is = " + stack.min());
}
}
参考自:http://hawstein.com/posts/3.2.html