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

news2024/11/27 0:41:00

一、前言

本题基于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).也是最小栈的最优解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1028997.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue-cli vue3

安装 cli npm i -g vue/cli4.5.13查看版本&#xff1a;vue -V升级版本&#xff1a;npm update -g vue/cli 升级 在 v 3.0.0 版本中是不支持的最新的 script setup 语法执行指令升级&#xff1a; npm i vue3.2.8 vue-router4.0.11 vuex4.0.2 "vue": "^3.2.8&q…

方案:AI赋能,森林防火可视化智能监管与风险预警系统解决方案

一、方案背景 森林火灾是世界八大自然灾害之一&#xff0c;具有发生面广、突发性强、破坏性大、危险性高、处置扑救特别困难等特点&#xff0c;严重危及人民生命财产和森林资源安全&#xff0c;甚至引发生态灾难。有效预防和及时控制森林火灾是保护国家生态建设成果、推进生态…

SOLIDWORKS三维剖视图怎么做

1.SOLIDWORKS一般剖视图制作方法&#xff0c; a.先选择剖面视图命令制作&#xff08;常用&#xff09; b.先绘制剖切线制作剖视图&#xff0c;绘制剖切线—选择剖面视图命令 2.SOLIDWORKS剖面线的调整。当对默认剖面线不满意时&#xff0c;可以双击剖面线对剖面线进行调整调整 …

Qt重写QTreeWidget实现拖拽

介绍 此文章记录QTreeWidget的重写进度&#xff0c;暂时停滞使用&#xff0c;重写了QTreeWidget的拖拽功能&#xff0c;和绘制功能&#xff0c;自定义了数据结构&#xff0c;增加复制&#xff0c;粘贴&#xff0c;删除&#xff0c;准备实现动态刷新数据支持千万数据动态刷新&a…

Postman应用——Pre-request Script和Test Script脚本介绍

文章目录 Pre-request Script所在位置CollectionFolderRequest Test Script所在位置CollectionFolderRequest Pre-request Script&#xff08;前置脚本&#xff09;&#xff1a;可以使用在Collection、Folder和Request中&#xff0c;并在Request请求之前执行&#xff0c;可用于…

整站抓取的神器

整站抓取的神器 TeleportUltraWebZipMihov Picture DownloaderWinHTTrack HTTrackMaxprogWebDumper 五款整站抓取的工具 TeleportUltra Teleport Ultra所能做的&#xff0c;不仅仅是离线浏览某个网页(让你离线快速浏览某个网页的内容当然是它的一项重要功能)&#xff0c;它可…

链表oj题2(Leetcode)(牛客)——合并两个有序链表;判断回文链表;链表分割

链表oj题2&#xff08;Leetcode&#xff09;&#xff08;牛客&#xff09; 一&#xff0c;合并两个有序链表1.1分析2.2代码 二&#xff0c;链表的回文结构2.1分析2.2代码 三&#xff0c;链表分割3.1分析3.2代码 四&#xff0c;小结 一&#xff0c;合并两个有序链表 合并两个有…

vue的工程化开发全流程,以及开发中的细节语法和用法

vue的工程化开发全流程 文章目录 vue的工程化开发全流程1、工程化开发&脚手架Vue CLI1.1、前言1.2、脚手架Vue CLI1.3、脚手架目录文件介绍&项目运行流程1.4、组件化开发&根组件1.5、普通组件的注册使用 2、工程化开发细则2.1、组件的三大组成部分2.2、组件的样式冲…

yolov8在设置amp=False 之后map 训练依旧为0 解决办法

可能原因 是cuda 版本导致的半精度浮点数计算出现nan的bug 解决办法 设置ampFalse 就是不使用混合精度训练。或者直接改用低版本的cuda和pytorch。cuda11.6 以下 直接有效也有可能是学习率过高 降低学习率 设置ampFalse之后还是存在问题 是因为yolov8库的问题 按以下修改 找到…

RKDevTool打包成update.img

(1) 准备好RKDevTool_Release和rockdev目录相关的文件工具 (2) 在rockdev建立image目录 (3) 往image填入和package-file有关的img文件 (4) 运行需要的xxx_mkupdate文件,直到生成想要的update.img (5) 导入烧录工具,文件大,需要等待一段时间,进入MASKROM模式,点击烧录upd…

我只是个小市民——经受不住宏大叙事

我只是个小市民 ——经受不住宏大叙事 作日看到一个曾经的朋友在朋友圈晒出了在某地旅游的照片&#xff0c;照片清新动人&#xff0c;狠狠地打入了我的内心&#xff0c;我知道光靠手机是拍不出来这样唯美的画面的&#xff0c;于是我问她是如何弄出这么好看的照片&#xff0c;…

淘宝商品sku数据接口监控

淘宝商品sku数据接口监控是指通过API接口对淘宝店铺的商品库存、价格、销售量等数据进行实时监控&#xff0c;以便商家能够及时调整销售策略、优化库存、了解竞争对手的动态等。 监控的具体功能包括&#xff1a; 实时监控商品库存和价格变化&#xff0c;及时调整自己的销售策…

数据结构前瞻

集合框架 JAVA的集合框架是定义在java.util包下的一组接口和实现类&#xff0c;用于将多个元素置于一个单元中&#xff0c;对这些元素进行快速&#xff0c;便捷的存储&#xff0c;减速和管理&#xff0c;即增删查改 下面的格子&#xff0c;黄色代表接口&#xff0c;蓝色代表抽…

监控办公室电脑用什么软件?

监控办公室员工电脑的工作情况是一项非常重要的管理任务&#xff0c;它可以帮助企业管理者及时发现员工的问题、提高工作效率和保障企业安全。以下是一些具体的方法和步骤&#xff0c;供您参考&#xff1a; 1、安装监控软件 在监控员工电脑之前&#xff0c;您需要先安装一款专…

Redis核心数据结构实战与高性能解析

目录 一、安装Redis 二、Redis线程与高性能 2.1 Redis是单线程么&#xff1f; 2.2 Redis读写是单线程为何这么快&#xff1f; 2.3 Redis如何处理并发操作命令&#xff1f; 三、核心数据结构实战 3.1 字符串常用操作实战 SET 存入键值对 SETNX SETEX MSET 批量存入键…

vue3中两个el-select下拉框选项相互影响

vue3中两个el-select下拉框选项相互影响 1、开发需求2、代码2.1 定义hooks文件2.2 在组件中使用 1、开发需求 如图所示&#xff0c;在项目开发过程中&#xff0c;遇到这样一个需求&#xff0c;常规时段中选中的月份在高峰时段中是禁止选择的状态&#xff0c;反之亦然。 2、代…

《Cesium 进阶知识点》- 关闭天空盒,自定义背景图

效果 关键代码 1.代码第 4 行&#xff0c;初始化时配置 webgl.alpha 为 true&#xff1b; 2.代码第 8 行&#xff0c;不显示天空盒&#xff1b; 3.代码第 9 行&#xff0c;背景色透明&#xff1b; const viewer new Cesium.Viewer(cesiumContainer, {contextOptions: {…

室内导航制作:从背景到实施效益的全面解析

室内导航市场需求的增长主要源于两方面&#xff1a;一是人们对便捷生活的追求&#xff0c;二是物联网、大数据、人工智能等技术的发展。在日常生活中&#xff0c;我们经常需要在复杂的环境中进行定位和导航&#xff0c;比如大型购物商场、机场、车站等。传统的室外导航方式无法…

雷龙CS SD NAND(贴片式TF卡)性能体验及应用

前段时间有幸得到了雷龙出品的贴片式的TF卡的芯片及转接板&#xff0c;从而对其产品进行了相应的了解和测评。 从获得的相关资料看&#xff0c;雷龙出品的贴片式芯片分为两类&#xff0c;即BOW型和AOW型&#xff0c;其中BOW型为第一代产品&#xff0c;属商业级&#xff1b;AOW…

评价实施范围

声明 本文是学习GB-T 42874-2023 城市公共设施服务 城市家具 系统建设实施评价规范. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件确立了城市家具系统建设实施的评价原则、评价流程&#xff0c;给出了评价指标&#xff0c;描述了 方…