leetcode题目分析(一)leetcode155最小栈

2023-09-21 17:45:44

一、前言

本题基于leetcode155最小栈这道题,说一下通过java解决的一些方法。
需要尤其注意的是,此题输入的值的区间范围在-2^31 <= val <= 2^31 - 1.这将会影响我们最后一种最优解的结果出现问题。这些都是后话。

二、解决思路

其实在一开始的提交记录,我的方案忽略了题干中的常数时间,而是使用了偏向于工程的,将栈的所有元素放到数组中,然后通过数组的stream流的min方法解决:

class MinStack {

private Stack<Integer> stack;
	public MinStack() {
		stack = new Stack<>();
	}

	public void push(int val) {
		stack.push(val);
	}

	public void pop() {
		stack.pop();
	}

	public int top() {
		return stack.peek();
	}

	public int getMin() {
		ArrayList<Integer> arrayList = new ArrayList<>();
		arrayList.addAll(stack.subList(0, stack.size()));
		return arrayList.stream().min(Integer::compare).get();
	}
}

在这里插入图片描述

那么实际上stream也是一个循环,但是结果过了,可能并没有对时间去做一个检测。但是这个解决方案时间复杂度和空间复杂度均为O(n),是最拉的方案。所以这里完全不推荐。那么下面我们说一下一些比较OK的正解

2.1、辅助栈

这也是最容易想到的一种解决方案,我们定义一个辅助栈。当栈为空的时候,对于主栈和辅助栈都存放该元素。如果不为空,每次push的时候,通过将当前要插入的元素和辅助栈的栈顶元素去做一个对比,如果要插入的元素比栈顶元素小,则push要插入的元素,反之push辅助栈的栈顶元素。这样我们可以保证我们的辅助栈的栈顶一定对应的最小值,而出栈查看栈顶判空都很简单:出栈两个栈都需要pop,查看栈顶返回我们主栈的栈顶元素,查看最小值返回我们辅助栈的栈顶元素即可。

class MinStack {

	private Stack<Integer> stack;
	private Stack<Integer> assistStack;

	public MinStack() {
		stack = new Stack<>();
		assistStack = new Stack<>();
	}

	public void push(int val) {
		if(stack.isEmpty()){
			stack.push(val);
			assistStack.push(val);
		}else {
			stack.push(val);
			assistStack.push(Math.min(assistStack.peek(), val));
		}
	}

	public void pop() {
		stack.pop();
		assistStack.pop();

	}

	public int top() {
		return stack.peek();
	}

	public int getMin() {
		return assistStack.peek();
	}
}

2.2、链表

我们可以通过自定义链表的方式,去定义一个节点,节点中增加一个属性min记录最小值,然后每次push的时候,类似链表的增加元素,而对于新的Node节点的min属性,思路很像上面辅助栈的思路,用要插入的值和head节点(其实就类似栈顶元素)的min做一个对比,如果要比min还小,则这个新节点的min就是要插入的值,反之是head节点的min.然后剩下的就是链表实现栈的常规操作了。代码如下:

class MinStack {

private Node head;
    
    public void push(int x) {
        if(head == null) 
            head = new Node(x, x);
        else
            //用当前要插入的值和头结点的最小值做一个对比
            head = new Node(x, Math.min(x, head.min), head);
    }

    public void pop() {
        head = head.next;
    }

    public int top() {
        return head.val;
    }

    public int getMin() {
        return head.min;
    }
    
    private class Node {
        int val;
        int min;
        Node next;
        
        private Node(int val, int min) {
            this(val, min, null);
        }
        
        private Node(int val, int min, Node next) {
            this.val = val;
            this.min = min;
            this.next = next;
        }
    }
}

上面两个思路都差不多,所以最终的解决时间空间也都差不多,时间复杂度是O(1),空间复杂度为O(n)
在这里插入图片描述

2.3、存差值

那有没有时间复杂度和空间复杂度均为O(1)的解决方案呢,其实是有的。
我们可以额外存储一个值记录当前最小值min,然后我们的栈不放常规元素了。放差值,这个差值就是要插入元素x和我记录的最小值min的差值。记diff = x-min,这样对于getMin()操作我就可以直接返回记录的min了
对于push操作
当栈为空栈时,此时min就是要插入的值,diff记为0,所以push(0),记min = x;
当栈不为空,此时计算diff
如果diff >= 0; 那么说明要插入的值>=最小值,此时我们push(diff),但是我的min是不需要变动的
如果diff < 0:那么说明要插入的值<最小值,此时push(diff),但是我们记录min = x;

对于pop操作
由于我的最小值是一直在变动的,所以我们仍然需要查看栈顶即diff的值
如果diff<0的出栈了,这说明此时我的一个最小值出栈了,那么此时我需要变动我的min为min = min-diff
例如我的diff = -1,我的min记录此时为-3,那么我的min应该变成-3-(-1) = -2;
如果diff >=0的出栈,那就出栈,不用变动

对于top操作
主要在于还原值
此时查看栈顶的diff值
如果diff<0,那么肯定当前栈顶的元素就是最小值,那么直接返回最小值min即可
如果diff>0,那么说明原来的元素要比最小值大diff,所以我应该返回min+diff;
那么代码如下:

class MinStack {

	private Stack<Integer> stack;
	private Integer min;

	public MinStack(){
		stack = new Stack<>();
		min = 0;
	}
	public void push(int x) {
		if(stack.isEmpty()){
			//一开始由于栈是空栈,所以我们放入0.diff=0
			stack.push(0);
			min = x;
		}else {
			//不为空时,我们存插入的值和最小值的差值
			int diff = x - min;
			stack.push(diff);
			//如果差值<0,说明要插入的比当前最小值还要小,此时更新最小值
			if(diff < 0){
				min = x;
			}
		}
	}

	public void pop() {
		Integer pop = stack.pop();
		//如果
		if(pop < 0){
			min = min - pop;
		}
	}

	public int top() {
		Integer diff = stack.peek();
		if(diff < 0){
			return min;
		}else {
			return min + diff;
		}
	}

	public int getMin() {
		return min;
	}
}

但是需要注意的是:如果没有进行数值范围限制,上面的方法能行吗?答是不行,因为数值没有限制的话,差值的计算可能会溢出。例如Leetcode本题就无法用这个方法,因为这个方法一开始的数值范围是-2^31 <= val <= 2^31 - 1.那么在pop计算min-diff会出现下面的一幕,:

在这里插入图片描述
不过我们需要掌握这种思路,这种思路的时空复杂度均为O(1).也是最小栈的最优解

更多推荐

让Pegasus天马座开发板实现超声波测距

在完成《让Pegasus天马座开发板用上OLED屏》后,我觉得可以把超声波测距功能也在Pegasus天马座开发板上实现。于是在箱子里找到了,Grove-UltrasonicRanger这一超声波测传感器。官方地址:https://wiki.seeedstudio.com/Grove-Ultrasonic_Ranger超

zabbix介绍及部署(五十一)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档目录一、zabbix的基本概述二、zabbix的构成1、Server2、web页面3、数据库4、proxy5、Agent三、zabbix的监控对象四、zabbix的常用术语五、zabbix的工作流程六、zabbix进程详解七、zabbix的监控框架7.1三

Blender骨骼动画简明教程

Blender是首选的开源3D动画软件之一。令人惊讶的是,开始创建简单的角色动画并不需要太多时间。一旦获得最终的3D角色模型,你就可以使用该软件的众多动画功能和工具将其变为现实。推荐:用NSDT编辑器快速搭建可编程3D场景例如,Blender的绑定工具将帮助你实现角色所需的动作。还可以使用软件的姿势编辑功能添加和操作姿

【Vue】el 和 data短小精湛的细节!

hello,我是小索奇,精心制作的Vue教程持续更新哈,花费了大量的时间和精力,总结拓展了很多疑难点,想要学习&巩固&避坑就一起学习叭~el与data的两种写法el共有2种写法el表达式主要用来在模板中展示数据,它可以输出简单的变量值,也可以调用方法。语法是${表达式}创建Vue实例对象的时候配置el属性先创建Vue实

python学习--定义python中的类

创建类的语法类的组成类属性实例方法静态方法类方法classStudent:#Student为类的名称(类名)由一个或多个单词组成,每个单词首字母大写,其余小写native_place='吉林'#直接写在类的变量,称为类属性def_init_(self,name,age):self.name=name#self.name

zabbix自定义模板,邮件报警,代理服务器,自动发现与自动添加及snmp

1.自定义监控内容zabbix监控模板大全:www.zabbix.com/integration…监控案例1:登录人数检测需求:某公司确定已经安装好zabbix监控系统,限制某台服务器登录人数不超过3个,超过3个就发出报警信息。该服务器(192.168.73.114)已经添加至zabbix监控系统中具体步骤步骤一:在客

MyBatis高级

文章目录一、动态sql1、if2、choose...when...otherwise...3、where4、set5、foreach6、trim7、Sql片段二、分页1、分页的使用步骤1.1、导入maven依赖2、mybatis配置文件中指定方言3、java代码测试三、mybatis多表查询1、一对一2、一对多3、多对

Docker 一键安装Confluence(已支持最新版本)

Docker一键安装Confluence(已支持最新版本)本文用于Confluence在Docker的安装,仅用于记录安装方式Jira也可以参考这种方式安装,只有细微差别转载请注明来源Linux安装可参考链接Windows安装可查考链接条件允许时,请优先选择CentOS7原生安装一、查找想要的版本跟着文档走,不想换版本

23个销量最高的3D扫描仪【2023】

如果你可以3D扫描它,你就可以3D打印它。市场上3D扫描仪的种类和质量非常丰富,机器尺寸、功能和价格各异。这样的选择虽然本身是一件很棒的事情,但也会让从无用的东西中挑选出宝石成为一件苦差事。推荐:用NSDT编辑器快速搭建可编程3D场景无论你是在寻找适合学生或业余爱好者的完美入门级扫描仪、具有更好软件和工作流程的更强大的

Talk | ICCV’23 清华赵天辰:Ada3D-基于动态推理的3D感知模型压缩及软硬件协同优化

​本期为TechBeat人工智能社区第533期线上Talk!北京时间9月21日(周四)20:00,清华大学博士生—赵天辰的Talk已准时在TechBeat人工智能社区开播!他与大家分享的主题是:“Ada3D-基于动态推理的3D感知模型压缩及软硬件协同优化”,他介绍了他们提出的动态推理框架Ada3D,并进一步介绍了在硬件

Nginx服务配置及相关模块

目录一.Nginx配置文件1.1.主配置文件解析1.2.子配置文件启用二.子配置文件使用2.1.创建虚拟主机实验2.2.基于端口虚拟主机实验三.Nginx模块3.1.access模块3.2.自定义错误页面3.3.状态页开启一.Nginx配置文件1.1.主配置文件解析①yum安装主配置文件位置:/etc/nginx/ng

热文推荐