问题描述:
实现一个栈,带有出栈(pop),入栈(push),取最小元素(getMin)三个方法。要保证这三个方法的时间复杂度都是O(1)。
问题分析:
假设存储元素的栈为ms栈;
主要的难点在于获取栈最小元素getMin()要保证其时间复杂度为O(1);
而且由于存在push()和pop()操作,栈中最小元素currMin随时可能会因为入栈元和弹出操作而发生动态变化,因此需要一种机制,能够时刻记录当前栈的最小元素;
这里,可以考虑用一个辅助栈aux,当ms栈的第一个元素入栈时,aux将第一个元素的索引0入栈;
那么后续如何来保证aux的栈顶元素实时记录着ms栈的最小元素的索引呢?
当入栈操作时,如果入栈元素小于当前栈中最小元素(aux栈顶元素所对应的元素),更新当前最小元素,并将新的最小元素的索引(也即是top值)入辅助栈;
当出栈操作时,如果出栈元素等于当前栈中最小元素,先将aux栈顶元素弹出,在更新当前最小元素;
如此操作可保证aux的栈顶元素实时记录着ms栈当前元素的最小值。
实现:
package agother; import java.util.ArrayList; import java.util.Stack; public class MinStack { private ArrayList<Integer> ms = new ArrayList<Integer>();//栈元素的存储借助ArrayList private Stack<Integer> aux = new Stack<Integer>();//辅助的普通栈 private int currMin = Integer.MAX_VALUE;//当前最小值 private int top = -1;//栈顶指针 public void push(int ele){ ms.add(ele); top++; if (ele < currMin) {//如果入栈元素小于当前栈中最小与元素,更新当前最小元素,并将新的最小元素的位置(也即是top值)入辅助栈 currMin = ele; aux.push(top); } } public Integer pop(){ if (top<0) {return null;} Integer ele = ms.remove(top); top--; if (ele == currMin) {//如果出栈元素等于当前栈中最小元素,更新当前最小元素为次小元素,并弹出aux栈顶元素。 aux.pop(); currMin = ms.get(aux.peek()); } return ele; } /* * 实际上,辅助栈的栈顶元素始终记录的是ms栈中最小元素的索引值 * 即是是在ms压栈或者出栈的过程中,通过调整,任然保持着这一事实 * 因此getMin()方法总能以O(1)的时间复杂度正确找到ms栈的最小元素 * */ public Integer getMin(){ if (aux.isEmpty()) { return null; }else { return currMin;//或者返回ms.get(aux.peek()) } } public int size(){ return top+1; } public static void main(String[] args) { // TODO Auto-generated method stub try { MinStack ms = new MinStack(); ms.push(10); ms.push(3); ms.push(5); ms.push(15); ms.push(2); ms.push(8); // System.out.println(ms.size()); // System.out.println(ms.getMin()); // System.out.println(ms.pop()); // System.out.println(ms.pop()); // System.out.println(ms.pop()); // System.out.println(ms.pop()); // System.out.println(ms.pop()); System.out.println(ms.getMin()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }