剑指Offer——题目20

/* 日期:2019.7.22
 * 作者:***
 * 功能:剑指offer 题目20
 * 
 * =====================================================
 * 问题描述:
 * 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数
 * 要求:(时间复杂度应为O(1))。
 * 
 * ======================================================
 * 思路详解:
 * 这道题目,说实在的,仅根据剑指offer的题目描述,我看了半天没明白题目什么意思。
 * 最后,得出个人对题目的理解:
 * 题目最大的要求就是,实现个人实现一个栈,并且,有个min函数,得到其栈中最小值
 * 那么,时间复杂的为O(1),也就是栈中内部,必须时刻维护这一个最小值
 * 当放进元素和取出元素的时候,维护这这个最小值!以达到要求的O(1)的时间复杂度。
 * 
 * 理解了题目,再来考虑思路:
 * 首先,最简单的考虑为,维护一个min值,每次进栈的时候,新元素与min进行比较
 * 从而改变或维护原来的min值,顺着这个思路,我们发现,当出栈的时候,就有问题了
 * 出栈的时候,怎么维护min值,假如,出栈的值等于min值,我们是改变min值吗?
 * 答案是不一定的,万一还有元素等于min值呢?假如确定了没有元素等于min值了,那接
 * 下来min值又应该等于多少呢?
 * 至此,我们发现这个思路是行不通的,但是也给了我们启发,那就是进栈简单,如何保证出栈的思路?
 * 这就启发我们,还要找到一种逻辑去维护一个min值的序列,依次大小保证!
 * 
 * 所以本题采用一个辅助栈来维护min的序列,之所以用栈维护,是因为,栈保证了其先进后出的顺序
 * 思路如下:
 * 当向栈中放进数据的时候,判断当前元素node与栈中原来min值的相对大小。
 * 如果,node大于min,则直接压入即可,辅助栈不需要改变
 * 如果,node小于min,则需要改变min值为node,并且辅助栈压入这个node值,保证辅助栈的栈顶一直是min
 * 如果,node等于min,仔细想想,其实和node小于min的操作一致
 * 
 * 以上思路保证了:
 * 进栈就不多说了,很简单,也很容易理解;
 * 出栈的时候,解决了我们上述分析的两个问题:
 * 1.出栈的值等于min值,我们是改变min值吗?
 * 2.假如确定了没有元素等于min值了,那接下来min值又应该等于多少呢?
 * 
 * 因为,我们辅助栈其实是种维护了某个特定序列的min值。
 * 当出栈元素等于min值的时候,无论剩余栈中元素有没有等于min值的了,我们都能确定
 * 新的min值就等于辅助栈中栈顶的下一元素。
 * 很简单,因为进栈进了几次,我们辅助栈也进了几次!
 * 所以,每出一次栈,我们辅助栈也减少了一次当前值。
 * 很巧妙的思想!其实,辅助栈中从上到小的序列是严格的非递减序列,
 * 始终保证了剩余元素的min值就是辅助栈的栈顶值!
 * 
 * */


package com.*******;

import java.util.*;
import java.util.Stack;		//使用java栈

//根据题目要求,是要构造出一个栈的数据结构,实现其方法min,求最小值
public class Main11 {

	private Stack<Integer> stack1 = new Stack<Integer>();	//实现要求的栈结构
	private Stack<Integer> stack2 = new Stack<Integer>();	//辅助栈去维护min值的相对序列
	
	int minValue = Integer.MAX_VALUE;
	
	public void push(int node) {	//放进栈中
        stack1.push(node);	//进栈操作,实现栈的基本操作
        
        if (node <= minValue) {		//比较新元素与原栈中的min值的相对大小
			minValue = node;			//改变min值
			stack2.push(minValue);	//辅助栈压入min值,注意这一步是整个算法的核心,保证了出栈的操作正确
		}
    }
    
    public void pop() {		//取出元素
    	if(stack1.isEmpty())	//栈为空,抛出异常
    		throw new RuntimeException();
    	
    	int top = stack1.peek();	//先取出栈顶,用于判断辅助栈是否需要改变
        stack1.pop();	//出栈操作
        
        if(stack2.peek() == top)	//判断当前删除元素的值是否等于min
        {
        	stack2.pop();	//删除元素等于min,那么辅助栈栈顶删除一次
        	if(stack2.isEmpty())
        		minValue = Integer.MAX_VALUE;
        	else
        		minValue = stack2.peek();
        }
    }
    
    public int top() {		//得到栈顶元素
        return stack1.peek();
    }
    
    public int min() {		//题目所求,得到其所含最小值
        return minValue;
    }
    
    //主函数,程序代码测试入口
    public static void main(String args[])
    {
    	Main11 main11 = new Main11();
    	
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	
    	main11.push(3);
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.push(4);
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.push(2);
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.push(3);
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.pop();
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.pop();
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.pop();
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    	main11.push(0);
    	System.out.println("当前栈中最小值为:"+main11.minValue);
    }
}

猜你喜欢

转载自blog.csdn.net/romantic_jie/article/details/96885267