剑指offer代码解析——面试题21包含min函数的栈
时间:2022-05-03
本文章向大家介绍剑指offer代码解析——面试题21包含min函数的栈,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目:实现一个栈,要求使用O(1)时间获取栈中最小值,O(1)执行pop、push操作。
分析:要获取栈的最小值,我们首先想到的思路就是使用一个全局变量记录最小值,当元素进栈时和该全局变量进行比较,若小于该全局变量,则更新最小值。这种方法有个致命的缺陷:如果这个最小值出栈了,那么当前栈的最小值该如何确定?
解决办法:我们可以再创建一个栈b,栈b的高度始终与栈a保持一致,栈顶元素保存当前栈a的最小值。
入栈:当元素入栈a后,该元素与栈b的栈顶元素进行比较,若小于栈b的栈顶元素,则将该元素入栈b,否则,将栈b原本的栈顶元素再次入栈b。
出栈:当栈a的栈顶元素出栈时,只需将栈b的栈顶元素也出栈即可。这样,栈b的栈顶元素始终是栈a的最小值。
首先,我们需要定义以下几个成员变量:
private int[] stack_a;//栈a底层使用数组存储
private int[] stack_b;//用于存储最小值的栈
private int top_a = -1;//栈a的实际深度
private int top_b = -1;//栈b的实际深度
private int max;//栈的最大深度
接着定义构造函数,用于初始化栈:
/**
* 构造函数
* @param max 栈允许的最大深度
*/
public Stack(int max){
this.max = max;
//初始化栈的底层数组
stack_a = new int[max];
//初始化用于存储最小值的数组
stack_b = new int[max];
}
然后定义入栈函数:
/**
* 入栈
* @param t 入栈的元素
* @return 返回入栈操作的结果
*/
public boolean push(int t){
//若栈已满
if(top_a==max-1){
System.out.println("栈已满!");
return false;
}
//入栈
{
//元素首先入栈a
stack_a[++top_a] = t;
//当前入栈元素与栈b的栈顶元素比较,若小与栈b的栈顶元素,则入栈b,否则将栈b的栈顶元素再次入栈
if(top_b==-1 || t<stack_b[top_b])//PS:top_b==-1表示:如果栈b为空,则直接将当前值当作最小值入栈
stack_b[++top_b]=t;
else{
stack_b[top_b+1]=stack_b[top_b];
top_b++;
}
}
return true;
}
最后定义出栈函数:
/**
* 出栈
* @return 返回栈顶元素
*/
public int pop(){
//若栈为空
if(top_a==-1){
System.out.println("栈为空!");
return -1;
}
//栈不为空时可以出栈
{
//栈b的栈顶元素出栈
top_b--;
//栈a的栈顶元素出栈
return stack_a[top_a--];
}
}
紧接着我们定义获取最小值函数:
/**
* 获取栈中的最小值
* @return 返回栈中最小值
*/
public int min(){
//若栈为空
if(top_a==-1){
System.out.println("栈为空!");
return -1;
}
//返回最小值
return stack_b[top_b];
}
最后我们进行测试:
/**
* 测试
*/
public static void main(String[] args){
//创建最大容量为10的栈
Stack stack = new Stack(10);
//栈为空时出栈
System.out.println("栈为空时出栈:");
stack.pop();
//入栈
System.out.println("n1,2,3,4,5依次入栈:");
stack.push(5);
stack.push(4);
stack.push(3);
stack.push(2);
stack.push(1);
//最小值
System.out.println("n最小值:"+stack.min());
//出栈
System.out.println("n出栈:"+stack.pop());
//最小值
System.out.println("n最小值:"+stack.min());
}
输出结果如下:
栈为空时出栈: 栈为空! 1,2,3,4,5依次入栈: 最小值:1 出栈:1 最小值:2
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 谈谈我对Vue钩子函数、生命周期的理解
- 浅谈Apache Shiro权限模块及数据库设计
- 企图变秃变强的第一天
- 企图变秃变强的第二天
- Lambda表达式和FastDfs文件上传
- Postman带token测试接口、找不到生产者、无法连接MySQL、禅道部署
- MyBatis-Plus调试配置,IllegaStateException,StringUtils补充
- NullException、Token的作用、Mapstruct用法
- 1.String类型字符串拼接2.IDEA清除缓存、热部署3.File的用法 4.Dubbo查询服务状态
- 1.Dubbo 常见错误及解决方法
- SpringBoot学习一:创建工程、pom文件
- SpringBoot学习二:基础配置
- Spring Boot 学习三:静态资源、整合 Thymeleaf 页面模板、@RestControllerAdvice
- SpringBoot学习四:日志框架、SpringBoot自动化配置
- SpringBoot学习五:错误处理、跨域支持