栈和队列OJ——括号匹配问题,用队列实现栈,用栈实现队列,设计循环队列

news2024/12/24 15:38:47

题目1——括号匹配问题

题目来源. - 力扣(LeetCode)

思路——辅助栈法

括号匹配问题是一个经典的计算机科学问题,常用于检查一个字符串中的括号是否正确匹配。这包括各种括号,如小括号“()”,大括号“{}”,尖括号“<>”以及方括号“[]”。

这个问题可以通过使用栈(Stack)来解决,因为栈的后进先出(LIFO)特性使得我们可以很方便地处理嵌套结构。

以下是使用栈来解决括号匹配问题的基本思路:

  1. 初始化一个空栈这个栈将用于存储尚未找到匹配项的左括号。

  2. 遍历输入字符串:对于字符串中的每个字符,我们执行以下操作:

    • 如果遇到左括号(如'(', '{', '<', '['),我们将其压入栈中。
    • 如果遇到右括号(如')', '}', '>', ']'),我们检查栈顶元素(如果存在)是否是对应的左括号。如果是,我们将栈顶元素弹出,表示找到了匹配项;如果不是或者栈为空,说明存在括号不匹配的情况,返回false。
  3. 检查栈是否为空:在遍历完整个字符串后,如果栈为空,说明所有括号都找到了匹配项,返回true;否则,栈中剩余的左括号没有找到匹配项,返回false。

这个算法的时间复杂度是O(n),其中n是输入字符串的长度,因为我们只需要遍历一次字符串。空间复杂度也是O(n),在最坏的情况下,栈中可能存储n/2个左括号(假设所有括号都是左括号)。

队列(Queue)通常用于处理具有先进先出(FIFO)特性的问题,不适合用于解决括号匹配问题,因为队列无法方便地处理嵌套结构。

代码实现

bool isValid(char* s) 
{
    ST st;
    StackInit(&st);
    while(*s)
    {
        if (*s == '(' 
        || *s == '{' 
        || *s == '[')
        {
            StackPush(&st, *s);
            ++s;
        }
        else
        {
            //遇到右括号了,但是栈里面没有数据
            //说明前面没有左括号,不匹配
            if (StackEmpty(&st))
            {
                StackDestroy(&st);
                return false;
            }

            STDataType top = StackTop(&st);
            StackPop(&st);
            if ((*s == '}' && top != '{')
            || (*s == ']' && top != '[')
            || (*s == ')' && top != '('))
            {
                StackDestroy(&st);
                return false;
            }
            else
            {
                s++;
            }
        }
    }

    //如果栈不是空,说有栈中还有左括号未出
    bool ret = StackEmpty(&st);
    StackDestroy(&st);
    return ret;
}

题目2——用队列实现栈

题目来源. - 力扣(LeetCode)

思路 

这道题目是为初级读者准备的,题目涉及到栈和队列两种数据结构。

栈是一种后进先出的数据结构,元素从顶端入栈,然后从顶端出栈。

队列是一种先进先出的数据结构,元素从后端入队,然后从前端出队。

我们可以使用一个队列来实现这一想法

使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元素。

入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。

由于每次入栈操作都确保队列的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。出栈操作只需要移除队列的前端元素并返回即可,获得栈顶元素操作只需要获得队列的前端元素并返回即可(不移除元素)。

由于队列用于存储栈内的元素,判断栈是否为空时,只需要判断队列是否为空即可。

代码实现

// 定义一个链表节点的结构体  
typedef struct tagListNode {  
    struct tagListNode* next;  // 指向下一个节点的指针  
    int val;                   // 节点的值  
} ListNode;  
  
// 定义一个栈的结构体  
typedef struct {  
    ListNode* top;  // 栈顶元素,指向栈顶节点的指针  
} MyStack;  
  
// 创建一个新的栈  
MyStack* myStackCreate() {  
    MyStack* stk = calloc(1, sizeof(MyStack));  // 使用calloc分配内存并初始化为0  
    return stk;  // 返回新创建的栈  
}  
  
// 向栈中压入一个元素  
void myStackPush(MyStack* obj, int x) {  
    ListNode* node = malloc(sizeof(ListNode));  // 为新节点分配内存  
    node->val = x;  // 设置新节点的值  
    node->next = obj->top;  // 新节点指向原来的栈顶  
    obj->top = node;  // 更新栈顶为新的节点  
}  
  
// 从栈中弹出并返回栈顶元素  
int myStackPop(MyStack* obj) {  
    ListNode* node = obj->top;  // 获取栈顶节点  
    int val = node->val;  // 获取栈顶节点的值  
    obj->top = node->next;  // 更新栈顶为下一个节点  
    free(node);  // 释放原来的栈顶节点  
    return val;  // 返回弹出的值  
}  
  
// 获取栈顶元素的值  
int myStackTop(MyStack* obj) {  
    return obj->top->val;  // 直接返回栈顶节点的值  
}  
  
// 判断栈是否为空  
bool myStackEmpty(MyStack* obj) {  
    return (obj->top == NULL);  // 如果栈顶为NULL,则栈为空  
}  
  
// 释放栈占用的内存  
void myStackFree(MyStack* obj) {  
    while (obj->top != NULL) {  // 当栈不为空时  
        ListNode* node = obj->top;  // 获取栈顶节点  
        obj->top = obj->top->next;  // 更新栈顶为下一个节点  
        free(node);  // 释放原来的栈顶节点  
    }  
    free(obj);  // 释放栈本身占用的内存  
}

题目3——用栈实现队列

题目来源. - 力扣(LeetCode)

 思路——双栈

使用栈来实现队列的原理主要基于两个栈的交互操作。栈(Stack)是一种后进先出(LIFO,Last In First Out)的数据结构,而队列(Queue)是一种先进先出(FIFO,First In First Out)的数据结构。因此,直接使用一个栈是无法实现队列的先进先出特性的。但是,通过两个栈的配合使用,我们可以模拟出队列的行为。

原理如下:

  1. 定义两个栈我们定义两个栈,stack1 和 stack2。stack1 只用于接收入队操作(enqueue)的元素,而 stack2 只用于执行出队操作(dequeue)。
  2. 入队操作:当需要进行入队操作时,我们直接将元素压入 stack1。此时,stack1 中的元素顺序是后进先出的,但我们还不能直接从 stack1 中弹出元素,因为这样会破坏队列的先进先出特性。
  3. 出队操作:当需要进行出队操作时,我们首先检查 stack2 是否为空。如果 stack2 不为空,我们直接从 stack2 的栈顶弹出元素即可,因为 stack2 中的元素顺序已经是先进先出的了。但是,如果 stack2 为空,我们就需要将 stack1 中的所有元素逐个弹出并压入 stack2,这样 stack2 中的元素顺序就变成了先进先出。然后,我们再从 stack2 的栈顶弹出元素进行出队操作。

通过这种方式,我们可以保证队列的先进先出特性得以维持。虽然使用两个栈会增加一些操作的复杂性(特别是在 stack2 为空时需要将 stack1 中的元素全部转移到 stack2),但整体上这种方法是可以有效实现队列的。

需要注意的是,当队列为空时,stack1 和 stack2 都应该是空的。同时,为了优化性能,我们可以在入队时尽量避免不必要的元素转移操作。例如,当 stack2 不为空时,我们可以直接将新元素压入 stack2 而不是 stack1,这样可以减少后续出队时的元素转移次数。但是,这种方法需要更复杂的逻辑来控制两个栈的使用,因此在实际实现时需要根据具体需求进行权衡。

 

 

此时出队栈为空,所以要将入队栈的第一个进入的元素放入出队栈 

 

此时出队栈不为空,执行出队操作 

 

 

 

 

 

代码实现

typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;

// 定义队列的结构体  
typedef struct {  
    ST pushst; // 入队栈  
    ST popst;  // 出队栈  
} MyQueue;  
  
// 初始化队列  
MyQueue* myQueueCreate() {  
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));  
    if (obj == NULL) {  
        perror("malloc fail");  
        return NULL;  
    }  
    STInit(&obj->pushst); // 初始化入队栈  
    STInit(&obj->popst);  // 初始化出队栈  
    return obj;  
}  
  
// 入队操作  
void myQueuePush(MyQueue* obj, int x) {  
    STPush(&obj->pushst, x); // 将元素推入入队栈  
} 

// 查看队首元素  
int myQueuePeek(MyQueue* obj) {  
    if (STEmpty(&obj->popst)) {  
        // 如果出队栈为空,则将入队栈中的元素全部倒入出队栈  
        while (!STEmpty(&obj->pushst)) {  
            STPush(&obj->popst, STPop(&obj->pushst));  
        }  
    }  
    return STTop(&obj->popst); // 返回出队栈的栈顶元素  
}  
  
// 出队操作  
int myQueuePop(MyQueue* obj) {  
    int front = myQueuePeek(obj);  
    STPop(&obj->popst); // 弹出出队栈的栈顶元素  
    return front;  
}  
  
// 检查队列是否为空  
bool myQueueEmpty(MyQueue* obj) {  
    return STEmpty(&obj->pushst) && STEmpty(&obj->popst);  
}  
  
// 释放队列内存  
void myQueueFree(MyQueue* obj) {  
    STDestroy(&obj->pushst);  
    STDestroy(&obj->popst);  
    free(obj);  
}  

题目4——设计循环队列

题目来源. - 力扣(LeetCode)

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

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

相关文章

Eagle for Mac:强大的图片管理工具

Eagle for Mac是一款专为Mac用户设计的图片管理工具&#xff0c;旨在帮助用户更高效、有序地管理和查找图片资源。 Eagle for Mac v1.9.2中文版下载 Eagle支持多种图片格式&#xff0c;包括JPG、PNG、GIF、SVG、PSD、AI等&#xff0c;无论是矢量图还是位图&#xff0c;都能以清…

你的网站还在使用HTTP? 免费升级至HTTPS吧

如果您的网站还在使用老的http协议&#xff0c;可以申请一个免费的SSL证书升级至https&#xff01; 具体步骤如下&#xff1a; 1 申请免费SSL证书 根据你的需求选择合适的SSL证书类型&#xff0c;如单域名证书&#xff0c;多域名证书、通配符证书 登录免费供应商JoySSL官网&…

18 JavaScript学习:错误

JavaScript错误 JavaScript错误通常指的是在编写JavaScript代码时发生的错误。这些错误可能是语法错误、运行时错误或逻辑错误。以下是对这些错误的一些常见分类和解释&#xff1a; 语法错误&#xff1a; 这类错误发生在代码编写阶段&#xff0c;通常是由于代码不符合JavaScrip…

排队叫号取号投屏语音播报小程序开源版开发

排队叫号取号投屏语音播报小程序开源版开发 多场景排队叫号系统&#xff0c;支持大屏幕投屏&#xff0c;语音播报叫号&#xff0c;可用于餐厅排队取餐、美甲店排队取号、排队领取、排队就诊、排队办理业务等诸多场景&#xff0c;助你轻松应对各种排队取号叫号场景。 功能特性…

IBM SPSS Statistics for Mac v27.0.1中文激活版:强大的数据分析工具

IBM SPSS Statistics for Mac是一款功能强大的数据分析工具&#xff0c;为Mac用户提供了高效、精准的数据分析体验。 IBM SPSS Statistics for Mac v27.0.1中文激活版下载 该软件拥有丰富的统计分析功能&#xff0c;无论是描述性统计、推论性统计&#xff0c;还是高级的多元统计…

C++进阶--智能指针

智能指针的概念 智能指针是C中的一个重要概念&#xff0c;用于管理动态分配的对象内存。它是一个类模板&#xff0c;通过封装原始指针&#xff0c;并在对象生命周期结束时自动释放内存&#xff0c;从而避免了内存泄漏和资源管理的繁琐工作。 C标准库提供了多种常见的智能指针…

MySQL常见问题与解决方案详述

MySQL&#xff1a;常见问题与解决方案详述 作为一款广泛使用的开源关系型数据库管理系统&#xff0c;MySQL对于初学者来说既充满吸引力又充满挑战。本文将列举初学者在使用MySQL过程中可能遇到的一些典型问题&#xff0c;并提供详细的解决方案&#xff0c;配以图片辅助说明&am…

Visual Studio 对 C++ 头文件和模块的支持

在 C 编程领域&#xff0c;头文件和模块的管理有时候确实比较令人头疼。但是&#xff0c;有许多工具和功能可以简化此过程&#xff0c;提高效率并减少出错的可能性。下面是我们为 C 头文件和模块提供的几种工具的介绍。 构建明细 通过菜单栏 Build > Run Build Insights&a…

Eudic欧路词典for Mac:专业英语学习工具

Eudic欧路词典for Mac&#xff0c;作为专为Mac用户设计的英语学习工具&#xff0c;凭借其简捷高效的特点&#xff0c;成为众多英语学习者不可或缺的助手。 Eudic欧路词典for Mac v4.6.4激活版下载 这款词典整合了多个权威词典资源&#xff0c;如牛津、柯林斯、朗文等&#xff0…

低代码技术的全面应用:加速创新、降低成本

引言 在当今数字化转型的时代&#xff0c;企业和组织面临着不断增长的应用程序需求&#xff0c;以支持其业务运营和创新。然而&#xff0c;传统的软件开发方法通常需要大量的时间、资源和专业技能&#xff0c;限制了企业快速响应市场变化和业务需求的能力。在这样的背景下&…

杰发科技AC7840——CAN通信简介(7)_波形分析

参考&#xff1a; CAN总线协议_stm32_mustfeng-GitCode 开源社区 0. 简介 隐形和显性波形 整帧数据表示 1. 字节描述 CAN数据帧标准格式域段域段名位宽&#xff1a;bit描述帧起始SOF(Start Of Frame)1数据帧起始标志&#xff0c;固定为1bit显性(b0)仲裁段dentify(ID)11本数…

HarmonyOS开发案例:【 自定义弹窗】

介绍 基于ArkTS的声明式开发范式实现了三种不同的弹窗&#xff0c;第一种直接使用公共组件&#xff0c;后两种使用CustomDialogController实现自定义弹窗&#xff0c;效果如图所示&#xff1a; 相关概念 [AlertDialog]&#xff1a;警告弹窗&#xff0c;可设置文本内容和响应回…

视频输入c++ 调用 libtorch推理

1、支持GPU情况 libtorch 支持GPU情况比较奇怪&#xff0c;目前2.3 版本需要在链接器里面加上以下命令&#xff0c;否则不会支持gpu -INCLUDE:?ignore_this_library_placeholderYAHXZ 2 探测是否支持 加一个函数看你是否支持torch&#xff0c;不然不清楚&#xff0c;看到…

数据库和表创建练习

一丶要求 1.创建一个数据库db_classes 2 创建一行表db_hero 3. 将四大名著中的常见人物插入这个英雄表 二丶创建db_classes一个数据库, 使用数据库默认的字符集 create database db_classes; 三丶创建一行表db_hero 1.先切换到我们创建的db_classes;数据库中 use db_class…

HTTP的MIME 类型(2024-04-27)

1、简介 MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准&#xff0c;用来表示文档、文件或字节流的性质和格式。 MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。 浏览器通常使用 MIME 类型&#xff08;而不是文件扩展名&…

打包的意义 作用等前端概念集合 webpack基础配置等

基础网页是什么&#xff1f; 在学校最基础的三剑客 原生JS CSS H5就可以开发静态网页了 对于浏览器而言也能识别这些基础的文件和语法&#xff0c;真正的所见即所得&#xff0c;非常直接。 为什么要使用框架库&#xff1f; 对于常用的前端框架而言&#xff0c;无论是Vue Rea…

【面试经典 150 | 回溯】组合

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;回溯 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回顾…

企业微信开发

侧边栏开发 企业内应用 创建应用 录入必要信息 配置 网页授权及JS-SDK 需要按照提示&#xff0c;把认证的txt暴露出来&#xff0c;能够访问即可。 下图为认证成功的截图 配置侧边栏工具栏 录入页面名称&#xff08;tab页展示名&#xff09;、页面URL 配置授权可信ip 用于…

boa交叉编译(移植到arm)

参考&#xff1a;CentOS7 boa服务器的搭建和配置-CSDN博客 以下操作在宿主机/编译平台操作&#xff1a; 1. 先执行[参考]1到3、 4.2、4.3、4.4、4.5 2. 修改MakeFile # 由以下&#xff1a; CC gcc CPP gcc -E # 改为&#xff1a; CC arm-linux-gnueabihf-gcc CPP arm-l…

019基于JavaWeb的在线音乐系统(含论文)

019基于JavaWeb的在线音乐系统&#xff08;含论文&#xff09; 开发环境&#xff1a; Jdk7(8)Tomcat7(8)MysqlIntelliJ IDEA(Eclipse) 数据库&#xff1a; MySQL 技术&#xff1a; JavaServletJqueryJavaScriptAjaxJSPBootstrap 适用于&#xff1a; 课程设计&#xff0c;毕…