【栈和队列】常见面试题
文章目录
- 1.[有效的括号](https://leetcode.cn/problems/valid-parentheses/description/)
- 1.1 题目要求
- 1.2 利用栈解决
- 2. [用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/description/)
- 2.1 题目要求
- 2.2 用队列实现栈
- 3.[用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/description/)
- 3.1 题目要求
- 3.2 用栈实现队列
- 4.[设计循环队列](https://leetcode.cn/problems/design-circular-queue/description/)
- 4.1 题目要求
- 4.2 设计循环队列
1.有效的括号
1.1 题目要求
判断所给字符串的括号是否有效。
有效的条件:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
1.2 利用栈解决
遍历给定字符串时,当我们遇到左括号时,把它入栈。目的是为了期望在后续的遍历中有一个相同类型的右括号与其匹配。
当我们遍历时遇到的是右括号,此时有3种情况:
1.栈为空,无法匹配返回false。
2.栈不为空,但不是与之匹配的左括号,返回false。
3.栈不为空,是与之匹配的左括号,继续遍历。
在2,3情况下,为了简化书写,我们可以先把栈顶元素出栈,用一个临时变量保存。
如果我们在遍历时都顺利通过,也不能代表这个字符串就是有效的。
比如这种情况:( ( ( ) )
遍历完后,栈中还会剩下(.
为此最后我们还需要判断栈是否为空,不为空返回false,为空返回true。
注意记得销毁栈
typedef struct stack
{char* a;int size;//写错了,代表top的意思int capacity;
}stack;void init(stack* ps)
{assert(ps);ps->a = (char*)malloc(sizeof(char)*4);ps->size = 0;ps->capacity = 4;
}bool empty(stack* ps)
{return ps->size == 0;
}void push(stack* ps,char x)
{assert(ps);if(ps->size == ps->capacity){char* tmp = (char*)realloc(ps->a,sizeof(char)*ps->capacity*2);if(tmp == NULL){perror("realloc");exit(-1);}ps->a = tmp;ps->capacity *= 2;}ps->a[ps->size] = x;ps->size+=1;
}
void pop(stack* ps)
{assert(ps);assert(ps->size>0);ps->size -= 1;
}char Top(stack* ps)
{assert(ps);assert(ps->size>0);return ps->a[ps->size-1];
}
void destory(stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->size = 0;ps->capacity = 0;
}
bool isValid(char* s) {stack st;init(&st);while(*s){if(*s == '('||*s == '['||*s == '{')push(&st,*s);else if(*s == ')'||*s == ']'||*s == '}'){if(empty(&st)){destory(&st);return false;}char top = Top(&st);pop(&st);if(*s == ')'&&top!='('||*s == ']'&&top!='['||*s == '}'&&top!='{'){destory(&st);return false;}}s+=1;}if(!empty(&st)){destory(&st);return false;}destory(&st);return true;
}
2. 用队列实现栈
2.1 题目要求
使用两个队列实现一个后入先出(LIFO)的栈
2.2 用队列实现栈
如何用两个队列来实现栈呢?我们知道队列是先进先出的。
先画两个队列出来。

此时插入了3个数据,为了让这两个队列实现后进先出的效果,我们得充分利用队列的特性。显然如果是栈,出数据是先出3的,但是队列的话是先出1。为了让队列先出3,我们就要把1和2先移动到另一个空队列中。

如此一来,就可以拿到3了。
那么用两个队列实现栈的主要逻辑就出来了。
首先是插入逻辑:有两种情况
1.两个队列都为NULL,随便插入一个队列
2.其中一个队列不为NULL,那么就把数据插入到不为NULL的队列。
然后就是删除逻辑:
在删除时,我们需要把有数据的一方队列的数据转移到没有数据的队列中,直到只剩下一个元素,这就是栈顶元素,用一个临时遍历存储完数据后就可以删除这个栈顶元素了。
再然后的返回栈顶元素:
因为不用删除的缘故,队列又提供返回队尾元素的功能,所以直接返回有数据的那个队尾元素即可。
最后都是一些简单的接口,相信大家没问题的。
typedef struct node
{int data;struct node* next;
}node;typedef struct queue
{node* head;node* tail;
}queue;void init(queue* q)
{assert(q);q->head = q->tail = NULL;
}void push(queue* q,int x)
{assert(q);node* newnode = (node*)malloc(sizeof(node));if(newnode == NULL){perror("malloc");exit(-1);}newnode->data = x;newnode->next = NULL;if(q->head == NULL){q->head = q->tail = newnode;}else{q->tail->next = newnode;q->tail = newnode;}
}void pop(queue* q)
{assert(q);assert(q->head);if(q->head == q->tail){free(q->head);q->head = q->tail = NULL;}else{node* next = q->head->next;free(q->head);q->head = next;}
}int size(queue* q)
{assert(q);node* cur = q->head;int count = 0;while(cur){count+=1;cur = cur->next;}return count;
}bool empty(queue* q)
{assert(q);return q->head == NULL;
}int top(queue* q)
{assert(q);assert(q->head);return q->head->data;
}int back(queue* q)
{assert(q);assert(q->head);return q->tail->data;
}
void destory(queue* q)
{assert(q);node* cur = q->head;while(cur){node* next = cur->next;free(cur);cur = next;}q->head = q->tail = NULL;
}typedef struct {queue q1;queue q2;
} MyStack;MyStack* myStackCreate() {MyStack* s = (MyStack*)malloc(sizeof(MyStack));init(&s->q1);init(&s->q2);return s;
}void myStackPush(MyStack* s, int x) {if(!empty(&s->q1)){push(&s->q1,x);}else{push(&s->q2,x);}
}int myStackPop(MyStack* s) {queue* em = &s->q1;queue* noem = &s->q2;if(!empty(em)){em = &s->q2;noem = &s->q1;}while(size(noem)>1){push(em,top(noem));pop(noem);}int t = top(noem);pop(noem);return t;
}int myStackTop(MyStack* s) {queue* em = &s->q1;queue* noem = &s->q2;if(!empty(em)){em = &s->q2;noem = &s->q1;}return back(noem);
}bool myStackEmpty(MyStack* s) {return empty(&s->q1)&&empty(&s->q2);
}void myStackFree(MyStack* s) {destory(&s->q1);destory(&s->q2);free(s);
}
3.用栈实现队列
3.1 题目要求
请使用两个栈实现先入先出队列
3.2 用栈实现队列
要用两个后进先出的栈实现先进先出的队列。先看图

为了实现队列,我们要把栈设计为一个进进数据栈,一个出数据栈。
当我们需要删除数据时,因为队列先进先出的特性,要出的数据为1,可是栈顶元素是3,所以我们需要把进数据栈的数据全部移动到出数据栈中,移动完后如图:

这样的话,程序的主体逻辑都出来了。
开始我们入数据的时候,全部都存储到pusht栈中。
然后当我们想要删除数据/读取队首元素时:会有两种情况
1.popt栈为空,那么我们就把pusht栈中的元素全部转移到popt栈。
2.popt栈不为空,直接取popt的栈顶元素就可以了。
为了简化代码,我们可以复用函数。先实现读取队首元素的功能(peek)再在删除队列元素时复用读取对手元素的功能。详见代码
最后都是写简单功能,大家看代码。
typedef struct stack
{int* a;int size;//写错了,代表top的意思int capacity;
}stack;void init(stack* ps)
{assert(ps);ps->a = (int*)malloc(sizeof(int)*4);ps->size = 0;ps->capacity = 4;
}bool empty(stack* ps)
{return ps->size == 0;
}void push(stack* ps,int x)
{assert(ps);if(ps->size == ps->capacity){int* tmp = (int*)realloc(ps->a,sizeof(int)*ps->capacity*2);if(tmp == NULL){perror("realloc");exit(-1);}ps->a = tmp;ps->capacity *= 2;}ps->a[ps->size] = x;ps->size+=1;
}
void pop(stack* ps)
{assert(ps);assert(ps->size>0);ps->size -= 1;
}
int Top(stack* ps)
{assert(ps);assert(ps->size>0);return ps->a[ps->size-1];
}
void destory(stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->size = 0;ps->capacity = 0;
}
int size(stack* ps)
{assert(ps);return ps->size;
}
typedef struct {stack pusht;stack popt;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));init(&q->pusht);init(&q->popt);return q;
}void myQueuePush(MyQueue* q, int x) {push(&q->pusht,x);
}int myQueuePeek(MyQueue* q) {if(empty(&q->popt)){while(!empty(&q->pusht)){push(&q->popt,Top(&q->pusht));pop(&q->pusht);}}return Top(&q->popt);
}int myQueuePop(MyQueue* q) {int top = myQueuePeek(q);pop(&q->popt);return top;
}bool myQueueEmpty(MyQueue* q) {return empty(&q->pusht)&&empty(&q->popt);
}
void myQueueFree(MyQueue* q) {destory(&q->pusht);destory(&q->popt);free(q);q = NULL;
}
4.设计循环队列
4.1 题目要求
设计一个大小为k的循环队列
4.2 设计循环队列
简单科普循环队列
这是一个循环队列

下面展示循环队列为空和为满时情形:
tail位置是不存储数据的,代表意思是队尾元素的下一个。

科普完成后,下面就是正式的题目讲解:
在初始化时,我们需要开k+1个空间,因为数组中的tial位是不存储数据的。
先写判断循环队列是否为空和为满的功能,写了两个函数书写其他函数时就比较轻松了。
正如上面所说,tail = head为空
为满的话,考虑到循环因素,我们需要利用取模操作。
为满就一种情况,head在tail前面,但是因为数组不像上面画的那样是一个环,所以为满就有了两种情况:
1.tial在head前面,多种情况
2.tail在head后面,在后面就一种情况,tail为k,head为0
(tail+1)%(k+1) = head就是判断条件。
后面的插入删除都没什么难点了,唯一要注意的就是当head和tial到达k时要注意下一步的操作。
还有返回队尾数据的,tail是指向队尾数据的下一个元素的!
typedef struct {int* a;int head;int tail;int k;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));q->a = (int*)malloc(sizeof(int)*(k+1));q->head = q->tail = 0;q->k = k;return q;
}
//函数声明
bool myCircularQueueIsEmpty(MyCircularQueue* q);
bool myCircularQueueIsFull(MyCircularQueue* q);bool myCircularQueueEnQueue(MyCircularQueue* q, int value) {if(myCircularQueueIsFull(q))return false;q->a[q->tail] = value;if(q->tail == q->k)q->tail = 0;elseq->tail+=1;return true;
}bool myCircularQueueDeQueue(MyCircularQueue* q) {if(myCircularQueueIsEmpty(q))return false;if(q->head == q->k)q->head = 0;elseq->head+=1;return true;
}int myCircularQueueFront(MyCircularQueue* q) {if(myCircularQueueIsEmpty(q))return -1;return q->a[q->head];
}int myCircularQueueRear(MyCircularQueue* q) {if(myCircularQueueIsEmpty(q))return -1;if(q->tail == 0)return q->a[q->k];elsereturn q->a[q->tail-1];
}bool myCircularQueueIsEmpty(MyCircularQueue* q) {if(q->head == q->tail)return true;return false;
}bool myCircularQueueIsFull(MyCircularQueue* q) {if((q->tail+1)%(q->k+1) == q->head)return true;return false;}void myCircularQueueFree(MyCircularQueue* q) {free(q);q = NULL;
}
完
相关文章:
【栈和队列】常见面试题
文章目录 1.[有效的括号](https://leetcode.cn/problems/valid-parentheses/description/)1.1 题目要求1.2 利用栈解决 2. [用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/description/)2.1 题目要求2.2 用队列实现栈 3.[用栈实现队列](https://le…...
关于float浮点值二进制存储和运算精度损失的话题
1.前言 浮点值的存储、运算都可能会带来精度损失,了解精度损失背后的机制原因方便我们更好的了解什么情况下会发生精度损失、什么情况下精度损失较大,以及思考怎么避免或减少精度损失。 2.知识点 (1)IEEE 754标准 EEE 754标准…...
python爬虫学习记录-请求模块urllib3
(文章内容仅作学习交流使用) urllib3是一个功能强大、条理清晰,用于HTTP客户端的第三方模块 urllib3-发送网络请求 使用urllib3发送网络请求时,需要先创建PoolManager对象,并使用该对象的request方法发送请求&#…...
谷粒商城实战笔记-133~135-城业务-商品上架-远程上架接口
文章目录 一,谷粒商城实战笔记-133-城业务-商品上架-远程上架接口1,开发目标2,详细设计2.1,提前建立索引2.2,构造批量操作请求参数2.3,使用HighLevelClient调用bulk请求保存数据 二,134-商城业务…...
【React】详解 App.js 文件
文章目录 一、App.js文件的基本结构1. 引入必要的模块2. 定义根组件3. 导出根组件 二、App.js文件的详细解析1. 函数组件与类组件函数组件类组件 2. 使用CSS模块3. 组织子组件4. 管理组件状态使用useState钩子使用state对象 三、App.js文件的最佳实践1. 保持组件的简洁和模块化…...
【ML】self-supervised Learning for speech and Image
【ML】self-supervised Learning for speech and Image 1. self-supervised Learning for speech and Image1.1 自监督学习在语音处理领域的方法及其特点1.2 自监督学习在图像处理领域的方法及其特点 2. Predictive Approach2.1 特点2.2 适用场景 3. contrastive Learning4. 语…...
青岛实训day24(8/8)
一.Python环境准备 1.查看有没有python3 yum list installed |grep python yum list |grep python3 最新安装3.12可以使用源码安装 2.下载安装python3 yum -y install python3 3.查看版本 [rootpython ~]# python3 --version Python 3.6.8 4.进入编辑 [r…...
*算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
刷题记录 101. 孤岛的总面积DFSBFS 102. 沉没孤岛DFSBFS *103. 水流问题*104. 建造最大岛屿 101. 孤岛的总面积 题目地址 本题要求不与矩阵边缘相连的孤岛的总面积。先将与四个边缘相连的岛屿变为海洋,再统计剩余的孤岛的总面积。无需再标识访问过的结点ÿ…...
设计模式 由浅入深(待完结)
一、设计模式是什么? 设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案。 二、设计模式有哪些? 1. 观察者模式 定义对象间的一种一对多(变化&#x…...
(第34天)645、最大二叉树
目录 645、最大二叉树题目描述思路代码 645、最大二叉树 题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大…...
Python知识点:如何使用Paramiko进行SSH连接与操作
使用Paramiko进行SSH连接与操作可以分为以下几个步骤: 安装Paramiko: 首先需要安装Paramiko库,可以使用pip进行安装: pip install paramiko建立SSH连接: 使用Paramiko连接远程服务器,需要提供服务器的地址、…...
代码随想录算法训练营第六天(一)|242.有效的字母异位词
LeetCode 242 有效的字母异位词 题目: 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 示例 1: 输入: s "anagram&q…...
数据结构 | 考研代码题之顺序表 | 1 查找L中值为e的数据元素若找到则返回其下标,若找不到则返回-1
文章目录 1 题目2 题解 1 题目 假设有一个顺序表 L,其存储的所有数据元素均为不重复的正数,查找L中值为e的数据元素,若找到则返回其下标,若找不到则返回-1。 2 题解 C语言代码: /*假设有一个顺序表 L,其…...
RLVF:避免过度泛化地从口头反馈中学习
人工智能咨询培训老师叶梓 转载标明出处 大模型在不同行业和个人中的广泛应用要求模型能够根据具体的用户反馈进行调整或定制,以满足细微的要求和偏好。虽然通过高层次的口头反馈来指定模型调整非常方便,例如“在给老板起草电子邮件时不要使用表情符号”…...
设计原则与思想-从项目实战中学习设计模式
文章目录 开源项目通过剖析Java JDK源码学习灵活应用设计模式1. 单例模式(Singleton Pattern)示例:`java.lang.Runtime`2. 工厂模式(Factory Pattern)示例:`java.util.Date`3. 观察者模式(Observer Pattern)示例:`java.util.Observable` 和 `java.util.Observer`4. 适…...
python中的类属性、实例属性、类方法、实例方法和静态方法
1. 类属性(类变量)和实例属性(实例变量) 在python中,类中的属性就是定义在类中的变量,简称成员变量;类中的行为就是定义在类中的方法,简称成员方法。成员变量又可分为类变量和实例变量,或者分为类属性和实例属性。成员…...
A股继续底部震荡,探底是否能成功?
真心的给股民朋友提个醒,不管你胆大还是胆怯,盘面上出现了1个反常信号,一起来看看: 1、今天两市低开高走,开始筑底了,任何一个主力,都是在无人问津的熊市布局,而在人声鼎沸的牛市离场…...
NPDP考前怎么复习?NPDP200问PDF版来啦~
距离NPDP下半年考试还有4个月的时间,现在正是备考的黄金期。 以下复习建议~ 01.制定详细计划 首先,根据考试大纲,可以将内容划分为几个模块,如新产品开发流程、市场研究、产品规划等,并为每个模块设定学习目标和时间…...
ajax图书管理项目
bootstrap弹框 不离开当前页面,显示单独内容,让用户操作 功能:不离开当前页面,显示单独内容,供用户操作步骤: 1.引入bootstrap.css和bootstrap.js …...
深入理解 Java SPI - 概念、原理、应用
零、前言 在当今互联网时代,应用程序越来越复杂,对于我们开发人员来说,如何实现高效的组件化和模块化已经成为了一个重要的问题。而 Java SPI(Service Provider Interface)机制,作为一种基于接口的服务发现…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...
