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);
}
相关文章
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
41 6
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
35 4
|
1月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
73 2
|
1月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
36 7
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
17 4
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
40 5
|
1月前
|
算法 Python
【Leetcode刷题Python】 LeetCode 2038. 如果相邻两个颜色均相同则删除当前颜色
本文介绍了LeetCode 2038题的解法,题目要求在一个由'A'和'B'组成的字符串中,按照特定规则轮流删除颜色片段,判断Alice是否能够获胜,并提供了Python的实现代码。
36 3
|
1月前
|
算法 Python
【Leetcode刷题Python】剑指 Offer 33. 二叉搜索树的后序遍历序列
本文提供了一种Python算法,用以判断给定整数数组是否为某二叉搜索树的后序遍历结果,通过识别根节点并递归验证左右子树的值是否满足二叉搜索树的性质。
15 3
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - II. 从上到下打印二叉树 II
本文提供了一种Python实现方法,用于层次遍历二叉树并按层打印结果,每层节点按从左到右的顺序排列,每层打印到一行。
28 3
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
Leetcode题目"剑指 Offer 21. 调整数组顺序使奇数位于偶数前面"的两种Python解决方案,一种是使用双端队列调整数组顺序,另一种是使用双指针法将奇数移到数组前半部分,偶数移到后半部分。
21 4