【Leetcode】155-最小栈

本文探讨了在常数时间内获取栈中最小元素的问题,提出了三种解决方案:使用辅助栈、修改数据结构存储每个元素及其当前最小值、仅使用一个变量和栈存储差值。这些方法避免了线性时间复杂度的全栈扫描。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意审题:要求常数时间(不能用排序算法)。
基本思想:由于题目要求只花费常数时间,故需要借助“以空间换时间”的思想。

初步思考,会想到每次入栈时记录下当前最小值,但是当栈顶元素就是最小值被删除后,当前最小值应该被更新为什么值呢?因此记录当前最小值是不够的,还需要记录之前最小值。

解法一

主要思想

使用辅助栈,在数据入数据栈时即考虑是否放入辅助栈,因此不用在调用getMin函数时重新全部扫描一遍数据栈内的元素,可直接从辅助栈中找到最小元素,花费的是常数时间而不是线性时间。

关键点-辅助栈的入栈与出栈
当辅助栈为空时,入栈;当待入数据栈的数小于或等于辅助栈栈顶的数时,入栈(该操作保证了辅助栈顶存放的一直都是当前最小的元素,每次入栈时都会新增记录当前最小值,同时保留之前的最小值);
当数据栈栈顶元素要出栈时,如果该元素与辅助栈顶元素相同,则辅助栈栈顶元素也要出栈,因为此时数据栈的最小元素已经出栈(此操作也通过更新辅助栈的栈顶元素,更新了保存的数据栈当前最小的元素);

代码样例

class MinStack:

    def __init__(self):
        self.stack = []
        self.helper = []

    def push(self, x: int) -> None:
    	self.stack.append(x)
        if len(self.helper)==0 or x<=self.helper[-1]:
        	self.helper.append(x)    
        	     			        
    def pop(self) -> None:
    	if self.helper[-1] == self.stack.pop():
    		self.helper.pop()           
    		 			
    def top(self) -> int:
        return self.stack[-1]
        
    def getMin(self) -> int:
        return self.helper[-1]

解法二

主要思想

仅有数据栈,但修改数据结构。存储每个元素时,同时在同一位置存储当前最小值。也就是将 元组(value, min) 作为一个整体存储在栈中。
因此在调用getMin函数时,可以直接获取栈顶元素中的min;
当删除栈顶元素时,剩下的栈顶元素中存储的也是元组(栈顶元素,当前最小值)。

代码样例

class MinStack:

    def __init__(self):
        self.stack = []

    def push(self, x: int) -> None:
    	if not self.stack:
    		self.stack.append((x, x))
    	elif x <= self.stack[-1][1]:
    		self.stack.append((x, x))
    	else:
    		self.stack.append((x, self.stack[-1][1]))
    	       	     			        
    def pop(self) -> None:
    	return self.stack.pop()[0]
    		 			
    def top(self) -> int:
        return self.stack[-1][0]
        
    def getMin(self) -> int:
        return self.stack[-1][1]

解法三

只用一个变量(存储当前最小元素)和一个栈(每个元素存储的是当时的栈顶元素与当时最小元素的差值)

入栈:

  • 当原本要入栈的元素x比当前最小元素curr_min大时,实际需要入栈的是diff=x-curr_min是一个正数,当前最小值无需更新;
  • 当原本要入栈的元素x比当前最小元素curr_min小时,实际需要入栈的是diff=x-curr_min是一个负数,当前最小值更新为x(实际上也等于curr_min=curr_min+diff这一点很重要,说明了当想要得到上一个最小值时用当前最小值curr_min减去diff即可,每次入栈保存的diff起到了保存过去最小值的作用);

出栈:

  • 当要出栈的数是负数时(对应入栈diff为负数的场景),说明当时原本需要入栈的元素x小于当时的当前最小值curr_mincurr_min已更新为出栈的元素curr_min=min(x, curr_min),因此出栈元素x应为curr_min;且出栈后需要更新当前最小值为curr_min=curr_min-diff
  • 当要出栈的数是正数时(对应入栈diff正数的场景),说明原需出栈的元素x大于当前最小值curr_min,还原需要出栈的元素x=diff+curr_min,无需更新当前最小值;

取栈顶元素:每次调用top()或pop()函数时,返回的是栈顶元素的值diff与当前最小值curr_min的和(因为x=diff+curr_min)。

代码样例(有bug。。。会溢出)

class MinStack:

    def __init__(self):
        self.stack = []
        self.curr_min = None

    def push(self, x: int) -> None:
        if not self.stack:
            self.curr_min = x
            self.stack.append(x - self.curr_min)
        else:
            self.stack.append(x - self.curr_min)
            self.curr_min = min(self.curr_min, x)

    def pop(self) -> None:
        if not self.stack:
            return None
        if self.stack[-1] < 0:
            res = self.curr_min
            self.curr_min -= self.stack.pop()
        else:
            res = self.stack.pop() + self.curr_min
        return res

    def top(self) -> int:
        if not self.stack:
            return None
        if self.stack[-1] < 0:
            return self.stack[-1]
        else:
            return self.stack[-1] + self.curr_min

    def getMin(self) -> int:
        return self.curr_min
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值