• 【刷题之路】LeetCode 面试题 03.02. 栈的最小值


    一、题目描述

    原题连接: 面试题 03.02. 栈的最小值
    题目描述:
    请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。

    示例:

    MinStack minStack = new MinStack();
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    minStack.getMin(); --> 返回 -3.
    minStack.pop();
    minStack.top(); --> 返回 0.
    minStack.getMin(); --> 返回 -2.

    二、解题

    1、方法1——“辅助栈”

    1.1、思路分析

    既然题目应经明确要求了,min操作的时间复杂度必须为O(1),那我们想用遍历的方法来找到最小值的想法也就不现实了,那我们应该怎样解决这个O(1)的问题呢?
    我们可以借助一个辅助的栈minStack,来存储当前栈中最小的值当我们每次执行push时候,就相应的将当前栈中最小的值也入到minStack中。即minStack的栈顶元素就是当前栈中最小的值:
    在这里插入图片描述

    具体的操作是:
    1、当栈为空时,统一将新压入栈的元素压入到Stack和minStack。
    2、当栈不为空时,如果新压入栈的元素小于minStack栈顶的元素,就将新的元素压入minStack中,否则则继续将minStack的栈顶元素压入minStack。

    然后当我们要执行min操作时,就直接返回minStack的栈顶元素及可。
    而当我们执行Pop弹栈操作时,则需要让Stack和minStack同步弹栈,以确保在任何情况下minStack的栈顶元素都为Stack中的最小值。
    有的朋友可以会有疑问:难道要在栈中再嵌套定义一个子栈,然后执行各项操作的时候同时对这个子栈在执行相应的接口?
    其实么这个必要,我们只需要在栈中额外定义一个存储结构来存储当前栈中的最小值即可。就比如我们选用数组来实现栈,那我们就再额外定义一个数组来存储栈中的最小值,比如下面这样:

    typedef struct {
        int *data;
        int size; // 当前栈中的数据个数
        int capacity; // 当前栈的容量
        int *minStack; // 数组模拟一个栈,存储对应的最小值
    } MinStack;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后其实size和capacity是可以被data和minStack共用的,因为它们是同步Push和Pop操作的。

    1.2、代码实现

    有了以上思路,那我们写起代码来也就水到渠成了:
    初始化工作:

    typedef struct {
        int *data;
        int size;
        int capacity;
        int *minStack; // 数组模拟一个栈,存储对应的最小值
    } MinStack;
    
    MinStack* minStackCreate() {
        MinStack *stack = (MinStack*)malloc(sizeof(MinStack));
        if (NULL == stack) {
            perror("malloc fail!\n");
            exit(-1);
        }
        stack->data = NULL;
        stack->minStack = NULL;
        stack->size = 0;
        stack->capacity = 0;
        return stack;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    压栈接口Push:
    因为data和minStack是同并且共用size和capacity的,所以在增容时候也需要同步增容data和minStack。

    void minStackPush(MinStack* obj, int x) {
        // 先检查是否需要增容
        if (obj->size == obj->capacity) {
            int newCapacity = obj->capacity == 0 ? 10 : 2 * obj->capacity;
            int *temp1 = (int*)realloc(obj->data, newCapacity * sizeof(int));
            if (NULL == temp1) {
                perror("realloc fail!\n");
                exit(-1);
            }
            int *temp2 = (int*)realloc(obj->minStack, newCapacity * sizeof(int));
            if (NULL == temp2) {
                perror("realloc fail!\n");
                exit(-1);
            } 
            obj->data = temp1;
            obj->minStack = temp2;
            obj->capacity = newCapacity;
        }
        if (obj->size == 0) {
            obj->minStack[obj->size] = x;
        } else {
            int min = x < obj->minStack[obj->size - 1] ? x : obj->minStack[obj->size - 1];
            obj->minStack[obj->size] = min;
        }
        obj->data[obj->size] = x;
        obj->size++;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    弹栈Pop接口:

    void minStackPop(MinStack* obj) {
        assert(obj->size != 0);
        obj->size--;
    }
    
    • 1
    • 2
    • 3
    • 4

    取栈顶Top接口:

    int minStackTop(MinStack* obj) {
        assert(obj->size != 0);
        return obj->data[obj->size - 1];
    }
    
    • 1
    • 2
    • 3
    • 4

    求最小值min接口:

    int minStackGetMin(MinStack* obj) {
        assert(obj->size != 0);
        return obj->minStack[obj->size - 1];
    }
    
    • 1
    • 2
    • 3
    • 4

    释放free接口:

    void minStackFree(MinStack* obj) {
        free(obj->data);
        free(obj->minStack);
        obj->data = NULL;
        obj->minStack = NULL;
        obj->size = 0;
        obj->capacity = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    【首测】两款OpenCV 人工智能深度相机OAK PoE
    信捷XD系列PLC程序远程上下载怎么做?
    SELinux,无semanage,Linux user到SELinux user的映射
    天线设计中的负载牵引
    【注意力机制】Self-attention注意力机制理论知识
    Spring Cache 带你飞(一)
    <一>对象使用过程中背后调用了哪些方法
    微信小程序隐私协议相关接口实际使用方式
    【云原生与5G】微服务加持5G核心网
    VSCode 好用的插件分享
  • 原文地址:https://blog.csdn.net/kk702392702/article/details/130901523