剑指offer 30. 包含min函数的栈

目录

原题链接

题目描述

解决方案

思路分析

核心思路

流程图解

操作细节

代码实现

Python 语言实现

C 语言实现

Java 语言实现

复杂度分析

总结

其他相似题目


原题链接

剑指offer_在线编程_牛客网 (nowcoder.com)

题目描述

定义一个栈的数据结构,并实现一个能够在常数时间内(O(1))获取栈的最小元素的min函数。要求在该栈中,调用minpush以及pop的时间复杂度都是O(1)。

题目要求各函数的调用总次数不超过20000次。

解决方案

思路分析

要在O(1)时间复杂度内实现获取栈的最小值,我们需要借助辅助栈来存储当前栈中每个元素入栈时的最小值。辅助栈中的栈顶元素始终是当前主栈中的最小元素。

核心思路

  1. 主栈(stack):用于存储所有入栈的元素。
  2. 辅助栈(minStack):用于存储主栈中对应位置的最小值。

流程图解

操作细节

  • push操作:将元素压入主栈,同时将该元素与当前辅助栈的栈顶元素(即当前最小值)进行比较。如果该元素小于或等于当前最小值,则也将该元素压入辅助栈。
  • pop操作:弹出主栈栈顶元素。如果该元素等于辅助栈的栈顶元素,则同时弹出辅助栈的栈顶元素。
  • min操作:直接返回辅助栈的栈顶元素,即当前栈中的最小值。

代码实现

下面是不同语言的代码实现:

Python 语言实现
class MinStack:
    def __init__(self):
        self.stack = []  # 主栈
        self.minStack = []  # 辅助栈,存储最小值

    def push(self, val: int) -> None:
        self.stack.append(val)
        if not self.minStack or val <= self.minStack[-1]:
            self.minStack.append(val)

    def pop(self) -> None:
        if self.stack:
            if self.stack[-1] == self.minStack[-1]:
                self.minStack.pop()
            self.stack.pop()

    def top(self) -> int:
        if self.stack:
            return self.stack[-1]
        return -1  # 栈为空时返回-1

    def min(self) -> int:
        if self.minStack:
            return self.minStack[-1]
        return -1  # 栈为空时返回-1
C 语言实现
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct StackNode {
    int data;
    struct StackNode* next;
} StackNode;

typedef struct {
    StackNode* top;
    StackNode* minTop;
} MinStack;

MinStack* minStackCreate() {
    MinStack* stack = (MinStack*)malloc(sizeof(MinStack));
    stack->top = NULL;
    stack->minTop = NULL;
    return stack;
}

void push(MinStack* stack, int val) {
    StackNode* node = (StackNode*)malloc(sizeof(StackNode));
    node->data = val;
    node->next = stack->top;
    stack->top = node;

    if (stack->minTop == NULL || val <= stack->minTop->data) {
        StackNode* minNode = (StackNode*)malloc(sizeof(StackNode));
        minNode->data = val;
        minNode->next = stack->minTop;
        stack->minTop = minNode;
    }
}

void pop(MinStack* stack) {
    if (stack->top == NULL) return;
    if (stack->top->data == stack->minTop->data) {
        StackNode* minNode = stack->minTop;
        stack->minTop = stack->minTop->next;
        free(minNode);
    }
    StackNode* temp = stack->top;
    stack->top = stack->top->next;
    free(temp);
}

int top(MinStack* stack) {
    return stack->top ? stack->top->data : -1;
}

int min(MinStack* stack) {
    return stack->minTop ? stack->minTop->data : -1;
}

void minStackFree(MinStack* stack) {
    while (stack->top != NULL) {
        StackNode* temp = stack->top;
        stack->top = stack->top->next;
        free(temp);
    }
    while (stack->minTop != NULL) {
        StackNode* temp = stack->minTop;
        stack->minTop = stack->minTop->next;
        free(temp);
    }
    free(stack);
}
Java 语言实现
import java.util.Stack;

class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minStack;

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

    public void push(int val) {
        stack.push(val);
        if (minStack.isEmpty() || val <= minStack.peek()) {
            minStack.push(val);
        }
    }

    public void pop() {
        if (!stack.isEmpty()) {
            if (stack.peek().equals(minStack.peek())) {
                minStack.pop();
            }
            stack.pop();
        }
    }

    public int top() {
        return stack.isEmpty() ? -1 : stack.peek();
    }

    public int min() {
        return minStack.isEmpty() ? -1 : minStack.peek();
    }
}

复杂度分析

  • 时间复杂度
    • pushpoptopmin操作的时间复杂度均为O(1)。
  • 空间复杂度:O(n),其中n为栈中的元素个数。为了支持O(1)的最小值操作,辅助栈可能需要存储与主栈相同数量的元素。

总结

通过使用一个辅助栈,我们可以在O(1)时间复杂度内实现对栈的最小值查询。辅助栈的栈顶始终保持当前栈的最小元素,使得min操作能够快速返回栈的最小值。

其他相似题目

leetcode LCR 147.最小栈

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值