[LeetCode]栈,队列相关题目(C语言实现)

news2024/11/14 21:50:25

文章目录

  • LeetCode20. 有效的括号
  • LeetCode225. 用队列实现栈
  • LeetCode232. 用栈实现队列
  • LeetCode622. 设计循环队列

LeetCode20. 有效的括号

题目

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

要求

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

思路
用栈实现

  1. 如果是左括号, 直接将左括号入栈
  2. 如果是右括号, 如果此时栈为空, 返回 false; 将栈顶元素弹出栈, 如果栈顶元素不是对应的左括号, 返回 false; 如果栈顶元素是对应左括号, 出栈
  3. 遍历完字符串, 判断此时栈是否为空. 为空返回 true; 不为空返回 false

代码实现

#define N 10000
bool isValid(char * s)
{
    char stack[N] = {0,};   //创建栈数组
    int top = 0;            //top指向栈顶元素的后一个空间
    char topVal = 0;        //用来存放栈顶元素

    while (*s)
    {
        //如果是左括号
        if (*s == '{' || *s == '(' || *s == '[')
        {
            //入栈
            stack[top] = *s;
            top++;
        }
        //如果是右括号
        else
        {
            //如果此时栈为空, 直接返回false
            if (top == 0)
            {
                return false;
            }

            topVal = stack[top - 1];    //得到栈顶元素
            top--;  //栈顶元素出栈

            //如果右括号不是其对应的左括号, 直接返回false
            if ((*s == ']' && topVal != '[')
            || (*s == ')' && topVal != '(')
            || (*s == '}' && topVal != '{'))
            {
                return false;
            }
        }
        s++;
    }

    //如果遍历完字符串, 栈仍为空, 则返回true
    if (top == 0)
        return true;
    else
        return false;
}

LeetCode225. 用队列实现栈

题目

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

OJ链接

要求

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false

思路

  1. 使用两个队列,一个队列no_empty_que存放已经存放的元素,另一个队列empty_que常空
  2. 当要压栈的时候,将元素压入no_empty_que
  3. 当要出栈的时候,将no_empty_que中除队尾元素全部存入empty_que,将队尾元素移出

实例
在这里插入图片描述

代码实现

typedef int QDataType;

// 链式结构表示队列
typedef struct QListNode
{
  struct QListNode* next;
  QDataType data;
}QNode;

// 队列的结构
typedef struct Queue
{
  QNode* front;    //指向队列头
  QNode* rear;     //指向队列尾
  int size;        //记录队列的元素个数
}Queue;

// 初始化队列
void QueueInit(Queue* q)
{
  assert(q);  //确保q合法

  q->front = q->rear = NULL;  //将头和为置为 NULL 
  q->size = 0;
}

// 判断队列是否为空, 如果为空返回非0, 非空返回0
int QueueEmpty(Queue* q)
{
  assert(q);  //确保q合法

  if (q->size == 0)
  {
    return 1;
  }
  else 
  {
    return 0;
  }
}

// 队尾入队列
void QueuePush(Queue* q, QDataType x)
{
  assert(q);  //确保q合法

  //创建新结点
  QNode* newNode = (QNode*)malloc(sizeof(QNode));
  newNode->data = x;
  newNode->next = NULL;

  //入队列
  if (QueueEmpty(q))
  {
    //如果队列为空,直接赋值
    q->front = q->rear = newNode;
  }
  else 
  {
    //如果队列不为空,直接尾插
    q->rear->next = newNode;
    q->rear = newNode;
  }

  q->size++;
}

// 队头出队列
void QueuePop(Queue* q)
{
  assert(q);  //确保q合法
  assert(!QueueEmpty(q)); //确保队列不为空

  if (q->size == 1)
  {
    //如果只有一个元素,头删的同时还要将尾指针置空
    free(q->front);
    q->front = q->rear = NULL;
  }
  else 
  {
    //如果不止一个元素,则只头删
    QNode* nextNode = q->front->next;
    free(q->front);
    q->front = nextNode;
  }

  q->size--;
}

// 获取头部元素
QDataType QueueFront(Queue* q)
{
  assert(q);  //确保q合法
  assert(!QueueEmpty(q)); //确保队列不为空

  return q->front->data;
}

// 获取尾部元素
QDataType QueueBack(Queue* q)
{
  assert(q);  //确保q合法
  assert(!QueueEmpty(q)); //确保队列不为空

  return q->rear->data;
}

// 获取队列元素个数
int QueueSize(Queue* q)
{
  assert(q);  //确保q合法

  return q->size;
}



// 销毁队列
void QueueDestroy(Queue* q)
{
  assert(q);

  while(!QueueEmpty(q))
  {
    QNode* nextNode = q->front->next;
    free(q->front);
    q->front = nextNode;
  }

  q->front = q->rear = NULL;
  q->size = 0;
}

//用两个队列构成一个栈
typedef struct 
{
    Queue queue1;
    Queue queue2;
} MyStack;


MyStack* myStackCreate() 
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&pst->queue1);
    QueueInit(&pst->queue2);

    return pst;
}

void myStackPush(MyStack* obj, int x) 
{
    if (!QueueEmpty(&obj->queue1))
    {
        QueuePush(&obj->queue1, x);
    }
    else
    {
        QueuePush(&obj->queue2, x);
    }
}



int myStackPop(MyStack* obj) 
{
    Queue* no_empty_que = &obj->queue1;
    Queue* empty_que = &obj->queue2;

    if (!QueueEmpty(&obj->queue2))
    {
        no_empty_que = &obj->queue2;
        empty_que = &obj->queue1;
    }

    //弹出有元素的队列直至只剩一个元素
    while (QueueSize(no_empty_que) > 1)
    {
        QueuePush(empty_que, QueueFront(no_empty_que));
        QueuePop(no_empty_que);
    }

    int pop = QueueFront(no_empty_que);
    QueuePop(no_empty_que);
    return pop;
}

int myStackTop(MyStack* obj) 
{
    if (!QueueEmpty(&obj->queue1))
    {
      return QueueBack(&obj->queue1);
    }
    else
    {
      return QueueBack(&obj->queue2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    return QueueEmpty(&obj->queue1) && QueueEmpty(&obj->queue2);
}

void myStackFree(MyStack* obj) 
{
    QueueInit(&obj->queue1);
    QueueInit(&obj->queue2);
    free(obj);
}

LeetCode232. 用栈实现队列

题目

你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):OJ链接

要求

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路

  1. 使用两个栈,一个专门负责压入数据push_stack,另一个专门负责弹出数据pop_stack
  2. 当push数据,直接将数据压入push_stack
  3. 当pop数据,如果pop_stack为空,先将push_stack中的数据压入,pop_stack,再接将pop_stack的栈顶弹出

实例
在这里插入图片描述

代码实现

typedef int STDataType;

typedef struct Stack
{
  STDataType* a;  //指向栈空间
  int top;        //栈顶
  int capacity;   //容量
}Stack;

// 初始化栈
void StackInit(Stack* ps)
{
  assert(ps);
  
  ps->a = NULL;     
  ps->top = 0;
  ps->capacity = 0;
}

//入栈
void StackPush(Stack* ps, STDataType data)
{
  assert(ps);       //确保ps合法

  //如果容量不够则扩容
  if (ps->capacity == ps->top)
  {
    int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;   //定义新的容量
    STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);  //开辟新的空间
    if (tmp == NULL)
    {
      perror("malloc error");
      exit(-1);
    }
    else 
    {
      ps->a = tmp;
      ps->capacity = newCapacity;
    }
  }

  //将数据入栈
  ps->a[ps->top] = data;
  ps->top++;
}

// 出栈
void StackPop(Stack* ps)
{
  assert(ps); //确保ps合法

  assert(!StackEmpty(ps));  //确保栈不为空
  ps->top--;

}

// 检测栈是否为空, 如果为空返回非零结果, 如果不为空返回 0
int StackEmpty(Stack* ps)
{
  assert(ps); //确保ps合法
  
  if (ps->top > 0)
  {
    return 0;
  }
  else 
  {
    return 1;
  }
}

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
  assert(ps);   //确保ps合法
  assert(!StackEmpty(ps));  //确保栈不为空

  return ps->a[ps->top - 1];
}

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
  assert(ps);   //确保ps合法
  return ps->top;
}

// 销毁栈
void StackDestroy(Stack* ps)
{
  assert(ps); //确保ps合法

  free(ps->a);
  ps->a = NULL;
  ps->capacity = 0;
  ps->top = 0;
}

typedef struct 
{
    Stack push_stack;
    Stack pop_stack;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* que = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&que->push_stack);
    StackInit(&que->pop_stack);

    return que;
}

void myQueuePush(MyQueue* obj, int x) 
{
    StackPush(&obj->push_stack, x);
}

int myQueuePop(MyQueue* obj) 
{
    int pop = myQueuePeek(obj);
    StackPop(&obj->pop_stack);

    return pop;
}

int myQueuePeek(MyQueue* obj) 
{
    //如果pop_stack是空的话,将push_stack的所有元素入pop_stack
    if (StackEmpty(&obj->pop_stack))
    {
        while (!StackEmpty(&obj->push_stack))
        {
          StackPush(&obj->pop_stack, StackTop(&obj->push_stack));
          StackPop(&obj->push_stack);
        }
    }
    //如果pop_stack不是空,直接取栈顶元素
    int peek = StackTop(&obj->pop_stack);

    return peek;
}

bool myQueueEmpty(MyQueue* obj) 
{
    return StackEmpty(&obj->push_stack) && StackEmpty(&obj->pop_stack);
}

void myQueueFree(MyQueue* obj) 
{
    StackDestroy(&obj->push_stack);
    StackDestroy(&obj->pop_stack);
    free(obj);
}

LeetCode622. 设计循环队列

题目

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。OJ链接

要求

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

思路

  1. 为了确保方便判断空和满情况,将循环队列的空间比设定长度加1
  2. 入队列和出队列相关frontrear不是简单的加一或减一
  3. rear指向队尾下一个空间,front指向队头元素

代码实现

typedef struct 
{
    int* a;     //存放队列元素
    int front;  //指向队头元素
    int rear;   //指向队尾下一个元素
    int k;      //循环队列的大小
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    cq->a = (int*)malloc(sizeof(int) * (k + 1));
    cq->front = cq->rear = 0;
    cq->k = k;
    
    return cq;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->front == obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    //如果满了,插入失败
    if (myCircularQueueIsFull(obj))
    {
        return false;
    }

    //如果不满,进行插入,注意rear的大小
    obj->a[obj->rear] = value;
    obj->rear = (obj->rear + 1) % (obj->k + 1);

    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    //如果没有元素,删除失败
    if (myCircularQueueIsEmpty(obj))
    {
        return false;
    }

    //直接修改front的值即可
    obj->front = (obj->front + 1) % (obj->k + 1);

    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/985841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构与算法系列4】长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0 。 示例 1: 输入&…

读书笔记-《ON JAVA 中文版》-摘要24[第二十一章 数组]

文章目录 第二十一章 数组1. 数组特性2. 一等对象3. 返回数组4. 多维数组5. 泛型数组6. Arrays的fill方法7. Arrays的setAll方法8. 数组并行9. Arrays工具类10. 数组拷贝11. 数组比较12. 流和数组13. 数组排序14. binarySearch二分查找15. 本章小结 第二十一章 数组 1. 数组特…

【Spring面试】一、SpringBoot启动优化与Spring IoC

文章目录 Q1、SpringBoot可以同时处理多少请求Q2、SpringBoot如何优化启动速度Q3、谈谈对Spring的理解Q4、Spring的优缺点Q5、Spring IoC容器是什么?作用与优点?Q6、Spring IoC的实现机制是什么Q7、IoC和DI的区别是什么Q8、紧耦合与松耦合的区别&#xf…

算法训练day38|动态规划 part01(理论基础、LeetCode509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯)

文章目录 理论基础什么是动态规划动态规划的解题步骤 509. 斐波那契数思路分析代码实现思考总结 70. 爬楼梯思路分析代码实现思考总结 746. 使用最小花费爬楼梯思路分析代码实现 理论基础 什么是动态规划 动态规划,英文:Dynamic Programming&#xff0c…

【虚拟机开不了】linux、centOS虚拟机出现entering emergency mode解决方案

按他的操作输入journalctl之后输入shiftg到日志最后查看报错发现是xfs(dm-0有问题) xfs_repair -v -L /dev/dm-0 reboot解决问题

生信豆芽菜-XGboost构建诊断模型

网址:http://www.sxdyc.com/xgboostBuilds 1、准备数据 训练集表达谱数据 训练集样本分组数据 验证集表达谱数据 验证集样本分组数据 2、提交等待运行结果即可 当然,如果不清楚数据是什么样的,可以选择下载我们的示例数据&#…

PostMan传时间参数一次性发送多次请求

文章目录 1. Date类型的参数, "date": "2023-09-07 22:01:51"格式会报错2. 在Pre-request Script预置时间3. 使用postman一次性发送多次请求 1. Date类型的参数, “date”: "2023-09-07 22:01:51"格式会报错 2. 在Pre-req…

NumPy模块:Python科学计算神器之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…

巨人互动|Google海外户Google分析的基础概念

Google Analytics(谷歌分析)是最受欢迎的网站分析工具之一。它为网站管理员提供了深入了解其网站访问者的机会,并通过数据分析提供有关网站流量、用户行为和转化率的洞察。 1、跟踪代码(Tracking Code) 跟踪代码是嵌入…

网络技术二十二:NATPPP

NAT 转换流程 产生背景 定义 分类 常用命令 PPP PPP会话建立过程 认证 PPP会话流程

pdf怎么转换成dwg格式?简单转换方法分享

当我们需要在CAD中编辑PDF文件中的向量图形时,将PDF转换成DWG格式是一个非常好的选择。因为PDF是一种非常流行的文档格式,很多时候我们会接收到PDF文件,但是PDF文件中的向量图形无法直接在CAD中编辑。而将PDF转换成DWG格式后,就可…

米贸搜什么是网站排名流量

当谈到数字营销时,你的网站应该作为线上营销的中心枢纽。包括:Ads付费广告、EDM邮件营销、SEO搜索引擎优化等都旨在吸引用户访问你的网站,并在网站上进行深度转化。 被广泛应用且最有效的营销策略之一就是SEO,流量排名是衡量网站受…

Editplus小技巧:一次删除连续的多个空格

Editplus小技巧: 一次删除连续的多个空格 AltDel 请看上图,文件中的多个空格 请看上图,使用快捷键很快就删除了,有点Vim的感觉,爽! 查看Editplus更多的快捷键: Tools>>Preferences 如…

学习Harmony之前必了解的术语,否则一脸懵

以下开发前必须了解 1. HarmonyOS SDK --- 官方SDK 2. DevEco Studio 官方开发工具 DevEco Studio 3.1配套支持HarmonyOS 3.1版本及以上的应用及服务开发,提供了代码智能编辑、低代码开发、双向预览等功能,以及轻量构建工具DevEco Hvigor 、本地模…

WMS系统中的出入库实时监控

一、定义: 出入库实时监控是指通过仓储管理系统(WMS)对仓库内部的物流活动进行实时跟踪、监控和控制的过程。它涉及到对货物的进出仓库、货位的变动、库存的数量和状态等信息的及时记录和更新,以便企业能够准确掌握库存情况、优化…

USB Server集中管控加密狗,浙江省电力设计院正在用

近日,软件加密狗的分散管理和易丢失性,给拥有大量加密狗的浙江省电力设计院带来了一系列的问题。好在浙江省电力设计院带及时使用了朝天椒USB Server方案,实现了加密狗的集中安全管控,避免了加密狗因为管理不善和遗失可能带来的巨…

智能配电房管理

智能配电房管理依托电易云-智慧电力物联网,利用先进技术手段,对配电房进行智能化、自动化的管理,以提高配电房的安全性、可靠性和效率。 智能配电房管理包括: 1.实时监测:通过传感器、监控设备等手段,对配…

小程序:实现翻页功能(解决数据过载)

效果 核心代码 ①wxml设置翻页标签 <view class"pagination" wx:if"{{list.length>0}}"> <view class"page-button" bindtap"prevPage">上一页</view> <view class"page-info">{{ page }}<…

Friend.tech热潮未过,在推特刷屏的TipCoin又是个啥?

Web3社交赛道风起云涌&#xff0c;Friend.tech的热潮还没过&#xff0c;最近又有一款名为Tip Coin社交项目在X&#xff08;前Twitter&#xff09;开始刷屏。 TipCoin作为一款社交类区块链项目依托于X平台&#xff0c;用户通过在X平台上发布内容来进行“挖矿”&#xff0c;获得项…

无涯教程-JavaScript - BITAND函数

描述 BITAND函数返回两个数字的按位" AND"。 语法 BITAND (number1, number2)争论 Argument描述Required/Optionalnumber1 Must be in decimal form and greater than or equal to 0.Requirednumber2Must be in decimal form and greater than or equal to 0.Req…