leetcode每日刷题

简介: leetcode每日刷题

今天给大家分享两道栈的题目,因为博主用的是C写的,所以需要调用栈,但是每个代码都放一个栈显得冗余,所以先把栈放在这里吧。

typedef int STDataType;
typedef struct Stack
{
  STDataType* a;
  int top;
  int capacity;
}ST;
void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps);
STDataType StackTop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);
void StackInit(ST* ps)
{
  assert(ps);
  ps->a = NULL;
  ps->top = ps->capacity = 0;
}
void StackDestory(ST* ps)
{
  assert(ps);
  free(ps->a);
  ps->a = NULL;
  ps->capacity = ps->top = 0;
}
void StackPush(ST* ps, STDataType x)
{
  assert(ps);
  //只能尾插
  if (ps->top==ps->capacity)
  {
  int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity * sizeof(STDataType));
  if (tmp == NULL)
  {
    perror("realloc fail");
    exit(-1);
  }
  ps->a = tmp;
  ps->capacity = newCapacity;
  }
  ps->a[ps->top] = x;
  ps->top++;
}
void StackPop(ST* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  --ps->top;
}
STDataType StackTop(ST* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  return ps->a[ps->top - 1];
}
bool StackEmpty(ST* ps)
{
  assert(ps);
  return ps->top == 0;
}
int StackSize(ST* ps)
{
  assert(ps);
  return ps->top;
}


🏆一、栈的压入、弹出序列


来源: leetcode:栈的压入、弹出序列


输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。


1669268042115.jpg


通过题目我们知道pushed和poped的元素个数一样,而且里面都不会出现重复元素。我们通过栈来解决这道题目。


🖊①引入栈实现


1、我们引入一个栈,设立一个pos指针指向pushed数组,设立一个pt指针指向poped数组。我们先遍历pushed数组,如果pos指针指向的元素和pt指针指向的元素不相同,那么就入栈,然后pos++。


2、如果pos指针指向的元素和pt指针指向的元素相同,如果栈不空,我们就要判断栈顶元素和pt指向poped数组元素是否一样,如果一样就pop出栈,pt++,如果不一样就break。


3、遍历完pushed数组,我们成功的标志是pt指向的poped数组能否走完!也就等价于栈是否为空,如果不空,就返回false。最后栈空或者pt走完poped数组就返回true。


bool validateStackSequences(int* pushed, int pushedSize, int* popped, int poppedSize)
{
    ST st;
    StackInit(&st);
    int pos=0;
    int pt=0;
    while(pos<pushedSize)
    {
        if(pushed[pos]==popped[pt])
        {
            pos++;
            pt++;
            while(!StackEmpty(&st))
            {
                if(StackTop(&st)==popped[pt])
                {
                    StackPop(&st);
                    pt++;
                }
                else
                    break;
            }
        }
        else
        {
            StackPush(&st,pushed[pos]);
            pos++;
        }
    }
    while(!StackEmpty(&st))
    {
        if(StackTop(&st)==popped[pt])
        {
            StackPop(&st);
            pt++;
        }
        else
        {
            return false;
        }
    }
    StackDestory(&st);
    return true;
}


🖊②模拟栈实现


1、上一种方式还有缺陷,我们其实对于不需要返回的空间,比如栈。如果我们不需要调用它的接口,比如这道题,大可不必引入栈,我们模拟一个栈(数组模拟)即可,开一个局部变量就行。


2、上面博主说过,判断为true的条件有两个,一个为pt指针能否成功遍历结束poped数组;一个为栈最后是否为空。上面的引入栈博主使用的是前一种方式,这里博主采用第二种方式,只需遍历一遍pushed数组,然后判断模拟栈是否为空。


bool validateStackSequences(int* pushed, int pushedSize, int* popped, int poppedSize)
{
    //top能不能返回到0
    if(pushedSize<1)
        return true;
    int stack[pushedSize];//数组模拟栈
    int top=0;
    for(int i=0,j=0;i<pushedSize;++i)
    {
        stack[top++]=pushed[i];
        while(top>0&&stack[top-1]==popped[j])
        {
            top--;
            j++;
        }
    }
    return top==0;//判断是否为空
}


🏆二、包含min函数的栈


来源:leetcode、包含min函数的栈


定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。


1669268215839.jpg


🖊①倒栈求min


这道题目比较有意思的就是求栈中最小数的接口函数。


我们想写求栈中最小数的接口,创建两个栈st1和st2,st1用于push,st2只有在求栈中最小数的时候,我们把st1中的数据不断pop,push到st2,然后在这个过程中找到最小的返回;需要注意我们找到最小后还需要把st2的数据再pop,push到st1.


时间复杂度:O(N)


空间复杂度:O(N)

typedef struct 
{
    ST st1;
    ST st2;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() 
{
    MinStack* obj=(MinStack*)malloc(sizeof(MinStack));
    StackInit(&obj->st1);
    StackInit(&obj->st2);
    return obj;
}
void minStackPush(MinStack* obj, int x) 
{
    StackPush(&obj->st1,x);
}
void minStackPop(MinStack* obj) 
{
    if(!StackEmpty(&obj->st1))
    {
        StackPop(&obj->st1);
    }
}
int minStackTop(MinStack* obj) 
{
    if(!StackEmpty(&obj->st1))
    {
        return StackTop(&obj->st1);
    }
    return -1;
}
int minStackMin(MinStack* obj) 
{
    int min=StackTop(&obj->st1);
    while(!StackEmpty(&obj->st1))
    {
        if(StackTop(&obj->st1)<min)
            min=StackTop(&obj->st1);
        StackPush(&obj->st2,StackTop(&obj->st1));
        StackPop(&obj->st1);
    }
     while(!StackEmpty(&obj->st2))
    {
        StackPush(&obj->st1,StackTop(&obj->st2));
        StackPop(&obj->st2);
    }
    return min;
}
void minStackFree(MinStack* obj) 
{
    StackDestory(&obj->st1);
    StackDestory(&obj->st2);
    free(obj);
}


🖊②辅助栈存最小


上面的时间复杂度能否再降呢?是可以的!因为我们上面主要麻烦的就是求最小需要倒栈,如果我们把最小的数都放到st2,只要取最小就到st2取。这样时间复杂度为O(1)。可能说的抽象,具体来说:


1、在st2 push进INT_MAX(这有利于我们存放第一个最小的数,也省去判断是否为第一个数),当我们往st1里面push数据时,把它和st2栈顶的元素比较,取最小存放到st2中,st2中栈的元素始终比st1多一个INT_MAX(需要注意)。


2、当调用取最小的接口时直接取st2的栈顶元素就是当前st1栈中的最小值,当pop掉一个元素时,st1和st2都需要pop掉栈顶。


我再来解释一下:


为什么往st1里面push数据,要和st2栈顶比较,并取最小放到st2呢?


1669268239461.jpg


比如这样,当往st1里面依次存-2,-1,0.对应st2里面存放的是-2,-2,-2。这样存会方便我们在取栈中最小时可以直接拿到,最小,因为只要st1中的-2没有被pop掉,栈中最小的始终为-2.而在pop时一并pop掉st1和st2的栈顶元素可以保证st2中始终存的是当前st1中最小的元素!!!

typedef struct 
{
    ST st1;
    ST st2;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() 
{
    MinStack* obj=(MinStack*)malloc(sizeof(MinStack));
    StackInit(&obj->st1);
    StackInit(&obj->st2);
    StackPush(&obj->st2,INT_MAX);
    return obj;
}
void minStackPush(MinStack* obj, int x) 
{
    int min=x<StackTop(&obj->st2)?x:StackTop(&obj->st2);
    StackPush(&obj->st1,x);
    StackPush(&obj->st2,min);
}
void minStackPop(MinStack* obj) 
{
    if(!StackEmpty(&obj->st1))
    {
        StackPop(&obj->st2);
        StackPop(&obj->st1);
    }
}
int minStackTop(MinStack* obj) 
{
    if(!StackEmpty(&obj->st1))
    {
        return StackTop(&obj->st1);
    }
    return -1;
}
int minStackMin(MinStack* obj) 
{
    if(!StackEmpty(&obj->st1))//因为我们刚开始存了一个int_max
        return StackTop(&obj->st2);
    return -1;
}
void minStackFree(MinStack* obj) 
{
    StackDestory(&obj->st1);
    StackDestory(&obj->st2);
    free(obj);
}
相关文章
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
63 6
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
56 4
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
125 2
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
43 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
4月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
72 7
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
56 5
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
33 4
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
Leetcode题目"剑指 Offer 21. 调整数组顺序使奇数位于偶数前面"的两种Python解决方案,一种是使用双端队列调整数组顺序,另一种是使用双指针法将奇数移到数组前半部分,偶数移到后半部分。
29 4