刷爆leetcode第七期 0018

news/2024/5/7 20:31:13/文章来源:https://blog.csdn.net/meihaoshy/article/details/127352333

刷爆leetcode第七期 0018

  • 题目编号0018 用队列实现栈
    • 第一步 定义结构体
    • 第二步 实现创建(初始化)
    • 第三步 删除接口函数
    • 第四步 返回头的值
  • 总结
    • 发现问题一
    • 发现问题二
  • 源码

题目编号0018 用队列实现栈

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

实现 MyStack 类:

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

注意:

你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/implement-stack-using-queues

在这里插入图片描述
我们先来分析下题目

要求用两个队列实现一个栈 并且实现四种操作

我们来看第一个Push操作

栈的特点是什么? 先进后出

队列的特点是什么? 先进先出

来看图

在这里插入图片描述

图上是两个队列

我们假设 注意啊 是假设

第一行的图 它就是一个栈

那么我们可以判断出 它的数据插入顺序就是 1 2 3 4 5

这个时候队列的头就是栈的尾

如果我们这个时候需要删除栈的头数据应该怎么办呢?

我们都知道队列的数据只能是从头开始出

也就是说 比如要将队列前面的1 2 3 4全部出完之后才能开始出 5

但是我们不可能会抛弃之前的数据啊

这个时候我们就想到了第二个队列的用处了

只需要将我Pop的数据使用第二个队列来接受就可以

实现起来的图大概是这样子

在这里插入图片描述

这个时候我们就能删除掉头数据了

如果需要再删除一个怎么办呢?

那么只需要将上面的操作再重复一次就好了

这个时候的插入数据只需要往不为空的队列插入数据就可以了

要求首元素就是返回队列的尾

要求尾元素就是返回队列的头

这里我做个思维导图给大家看看

在这里插入图片描述

接下来我们来实现代码

把所有的队列代码以及接口函数拷贝进去

第一步 定义结构体

我们来看这个 我们应该怎么定义我们的Stack结构体呢?

既然是两个队列的实现的

那么是不是可以放两个队列的结构在里面?

仔细一想好像可行

我们来试试
在这里插入图片描述

代码表示如下

typedef struct 
{Queue q1;Queue q2;
} MyStack;

第二步 实现创建(初始化)

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

代码表示如上

这里我们需要判断哪个队列不为空

哪个不为空就插入哪里

第三步 删除接口函数

终于来到最难的一步了

我们先写出两个指针来判断空和非空

如果说我们的判断不正确的话 那么我们就将这两个指针翻转一下就好了

代码整体表现不变

    assert(obj);// 我们假设队列q1为空Queue* Empty = &obj->q1;Queue* NonEmpty = &obj->q2;// 如果队列1不为空的话 我们只需要将这两个指针的位置互换一下就可以 if(QueueEmpty(obj->q1)){;}else{Queue* Empty = &obj->q2;Queue* NonEmpty = &obj->q1;}

大家来感受下上面这段代码奇妙的地方

我们可以省略下面一大段的else代码

之后我们开始一个个的迁移数据

直到最后一个的时候我们记录下这个数据再删除

int myStackPop(MyStack* obj) 
{assert(obj);// 我们假设队列q1为空Queue* Empty = &obj->q1;Queue* NonEmpty = &obj->q2;// 如果队列1不为空的话 我们只需要将这两个指针的位置互换一下就可以 if(QueueEmpty(&obj->q1)){;}else{Empty = &obj->q2;NonEmpty = &obj->q1;}// 一个一个转移元素while(QueueSize(NonEmpty)>1){QueuePush(Empty,QueueFront(NonEmpty));QueuePop(NonEmpty);}// 记录下删除值 删除掉int pop = QueueFront(NonEmpty);QueuePop(NonEmpty);return pop
}

第四步 返回头的值

这里我们可以分两种情况讨论

如果1为空就返回2的尾值

如果2为空就返回1的尾值

int myStackTop(MyStack* obj) 
{// 断言assert(obj);// 返回不为空的那个队列的尾值if(QueueEmpty(&obj->q1)){return QueueBack(&obj->q2);}else{return QueueBack(&obj->q1);}
}

总结

发现问题一

这里一定要注意一个大坑!!

看看下面这段代码 有没有什么问题?
在这里插入图片描述

这里!!!! 仔细看
在这里插入图片描述
我们再定义了空和非空之后 又在语句块里面定义了一个空和非空

这里问题就很大了

语句块里面是不会改变Empty和NonEmpty的值的

而且更关键的是它不会报错!!!!

(害我debug了半个小时)

所以说大家再写代码的时候尽量将所有需要用的变量在开头定义一遍

在后面不能再定义了!

发现问题二

这里还要有要注意的一点

指针指向的东西不一定是指针

这点属于我的个人理解偏差

就比如说

我们在代码中写出了以下代码

obj->q1

这里获取的其实是q1这个结构体

要想将其作为参数传给指针的话必须要先传地址

源码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<assert.h>
#include<stdbool.h>typedef int QueueNodeType;typedef struct QueueNode
{struct QueueNode * next;QueueNodeType val;
}QueueNode;typedef struct Queue
{struct QueueNode* head;struct QueueNode* tail;
}Queue;void QueueInit(Queue* pq);
void QueuePush(Queue* pq, QueueNodeType x);
void QueuePop(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePrint(Queue* pq);
QueueNodeType QueueFront(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);QueueNodeType QueueBack(Queue* pq)
{// 断言assert(pq);assert(pq->tail);// 返回尾值return pq->tail->val;
}void QueueInit(Queue* pq)
{assert(pq);pq->head = NULL;pq->tail = NULL;
}
struct QueueNode* Buynewnode()
{struct QueueNode* newnode = (struct QueueNode*)malloc(sizeof(struct QueueNode));assert(newnode);return newnode;
}void QueuePush(Queue* pq ,QueueNodeType x)
{assert(pq);struct QueueNode* newnode = Buynewnode();assert(newnode);// 赋值newnode->val = x;newnode->next = NULL;// 判断头尾指针是否为空if (pq->head==NULL){pq->head = pq->tail = newnode;}// 赋值并链接else{pq->tail->next = newnode;pq->tail = newnode;}}void QueueDestroy(Queue* pq)
{// 断言不为空assert(pq);//assert(pq->head);// 删除数据 释放空间 头指针向后移动// 这里肯定要循环删除的 注意循环的条件while (pq->head){// 保存下一位struct QueueNode* cur = pq->head->next;// 删除迭代free(pq->head);pq->head = cur;}// 要注意 这里画图看看 删除掉最后一个节点的时候尾指针变空指针了 所以要对尾指针也进行赋值 pq->tail = NULL;
}void QueuePop(Queue* pq)
{//断言assert(pq);assert(pq->head);//每次删除一个 如果头指针指向空了 尾指针也要置空(野指针)// 保存下一位struct QueueNode* cur = pq->head->next;// 删除迭代free(pq->head);pq->head = cur;if (pq->head==NULL){pq->tail = NULL;}
}void QueuePrint(Queue* pq)
{//判断不为空assert(pq);//肯定还是用循环 打印一个删除一个 注意条件while (pq->head){printf("%d-> ", pq->head->val);// 在删除的时候head已经迭代了 我们不用管QueuePop(pq);//在最后的时候}// 形象表示下 这里加个空指针 可以不打printf("NULL\n");
}QueueNodeType QueueFront(Queue* pq)
{// 断言assert(pq);assert(pq->head);// 返回return pq->head->val;
}int QueueSize(Queue* pq)
{// 断言assert(pq);// 遍历 遇到NULL结束 开始就遇到NULL返回0int n = 0;struct QueueNode* cur = pq->head;while (cur){cur = cur->next;n++;}return n;
}bool QueueEmpty(Queue* pq)
{//断言assert(pq);return pq->head == NULL;
}typedef struct 
{Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate()
{// 使用动态内存开辟来返回值MyStack* obj = (MyStack*)malloc(sizeof(MyStack));// 很重要 这里还要对q1 q2进行初始化QueueInit(&obj->q1);QueueInit(&obj->q2);return obj; // 返回这个指针 想想看可不可以不用动态内存 怎么办? const?
}void myStackPush(MyStack* obj, int x) 
{assert(obj);if (QueueEmpty(&obj->q1)){QueuePush(&obj->q2,x);}else{QueuePush(&obj->q1,x);}
}int myStackPop(MyStack* obj) 
{assert(obj);// 我们假设队列q1为空Queue* Empty = &obj->q1;Queue* NonEmpty = &obj->q2;// 如果队列1不为空的话 我们只需要将这两个指针的位置互换一下就可以 if(QueueEmpty(&obj->q1)){;}else{Empty = &obj->q2;NonEmpty = &obj->q1;}// 一个一个转移元素while(QueueSize(NonEmpty)>1){QueuePush(Empty,QueueFront(NonEmpty));QueuePop(NonEmpty);}// 记录下删除值 删除掉int pop = QueueFront(NonEmpty);QueuePop(NonEmpty);return pop;
}bool myStackEmpty(MyStack* obj)
{//断言assert(obj);// 两个队列都为空就是空return QueueEmpty(&obj->q2) && QueueEmpty(&obj->q1);
}int myStackTop(MyStack* obj) 
{// 断言assert(obj);// 返回不为空的那个队列的尾值if(QueueEmpty(&obj->q1)){return QueueBack(&obj->q2);}else{return QueueBack(&obj->q1);}
}void myStackFree(MyStack* obj) 
{QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}/*** Your MyStack struct will be instantiated and called as such:* MyStack* obj = myStackCreate();* myStackPush(obj, x);* int param_2 = myStackPop(obj);* int param_3 = myStackTop(obj);* bool param_4 = myStackEmpty(obj);* myStackFree(obj);
*/

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET周报【10月第1期 2022-10-11】

本周精选 继C#实现await/async无栈协程几年后,davidwrighton实现了.NET绿色线程(有栈协程)的原型 https://github.com/dotnet/runtimelab/pull/2002 .NET Runtimelab中绿色线程的原型实现的PR,在不久的将来,.NET开发者也可以方便的用上有栈协程,目前的启动一个有栈协程的AP…

docker:基础命令未完待续

基础操作 docker info #查看docker的基本信息docker version #查看docker版本信息一、镜像操作 1、搜索镜像 docker search nginx2、下载镜像 docker pull nginx#从仓库中下载镜像&#xff0c;若没有指定标签&#xff0c;则下载最新的版本&#xff0c;也就是标签为: la…

Python快速刷题网站——牛客网 数据分析篇(十五)

&#x1f466;&#x1f466;一个帅气的boy&#xff0c;你可以叫我Love And Program &#x1f5b1; ⌨个人主页&#xff1a;Love And Program的个人主页 &#x1f496;&#x1f496;如果对你有帮助的话希望三连&#x1f4a8;&#x1f4a8;支持一下博主 前言 本文将继续学习pan…

MySQL的行锁、间隙锁和临建锁

目录 行锁 间隙锁&临键锁 行锁 InnoDB实现了以下两种类型的行锁&#xff1a; 共享锁&#xff08;S&#xff09;&#xff1a;允许一个事务去读一行&#xff0c;阻止其他事务获得相同数据集的排它锁。 //共享锁和共享锁兼容&#xff0c;共享锁和排他锁互斥。 排他锁&#…

43 多个相同限定名类型同时存在导致的继承结构混乱的情况

前言 // 四刷天府绿道 呵呵 在前面文章中 jetty-runner:jar:9.3.20 和 tomcat-embed-core-8.5.29 的 JarScannerCallback 不兼容, 导致服务启动失败 提到了这样的一个问题 我们再看一下这里的 callback 的接口, jetty-runner 的这个对象里面是没有 void scan(Jar jar, Str…

【附源码】计算机毕业设计SSM民宿短租系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

JavaEE - Servlet(向服务器上传文件 Part类)

我们在需要向服务器上传文件时&#xff0c;在前端需要使用form表单&#xff0c;form表单需要使用特殊的类型 form-data 此时提交文件的时候&#xff0c;浏览器会把文件内容以form-data的格式构造到HTTP请求中&#xff0c;服务器就可以通过getPart获取了 需要注意&#xff1a;…

2.idea 标定相关

1.发现 VINS对于参数准确性的要求高于ORBSLAM。依据是相同的参数,ORBSLAM可以提供准确的定位结果,但是VINS很容易就会发散。在线标定外参很有效,经历过几次外参标定以后的外参给VINS可以获得很好的效果,但是不排除只是针对这个场景,随后测试如果效果好,考虑给ORBSLAM3增加…

Redis常见的问题

① 缓存雪崩 缓存雪崩是指在短时间内&#xff0c;有⼤量缓存同时过期&#xff0c;导致⼤量的请求直接查询数据库&#xff0c;从⽽对数据库造成 了巨⼤的压⼒&#xff0c;严重情况下可能会导致数据库宕机的情况叫做缓存雪崩。 我们先来看下正常情况下和缓存雪崩时程序的执⾏流…

docker安装tomcat、mysql、redis

一、tomcat 1.下载tomcat8docker pull tomcat:8.5.612.启动容器(-d 后台启动)docker run -d -p 8080:8080 tomcat:8.5.61 3.访问首页http://ip:8080/访问不到 404 解决:需要修改tomcat下的文件夹 如下 进入后webapps.dist改为webapps 二、mysql 1.拉取mysqldocker pull mys…

网课题搜答案公众号接口系统

网课题搜答案公众号接口系统 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xf…

分布式数据库的基本概念

1.分布式数据库系统的产生和定义 产生原因: 经济的发展&#xff1a;经济发展&#xff1a;跨国公司&#xff1a;产生一个地方需要管理另外一个地方数据的需求 发展历程&#xff1a; 20世纪70年代末 成长于80年代 第一个数据库系统SDD-1是美国计算机公司(CAA)于1976年-1978年…

浏览器插件官方demo学习(一):基本代码、页面渲染、书签、cookie、Omnibox等

前言 参考&#xff1a;https://github.com/GoogleChrome/chrome-extensions-samples 官方目前只提供了几个基于v3版本的例子&#xff0c;其他例子都是基于v2版本的&#xff08;可能是官方比较忙&#xff0c;没空写例子吧&#xff09;。先从v3版本的例子开始学习&#xff0c;后…

JVM(六) —— 运行时数据区之堆的详细介绍(一)

JVM&#xff08;六&#xff09; —— 运行时数据区之虚拟机栈的详细介绍核心概述堆空间代码演示堆空间划分&#xff08;重要&#xff09;一个Java程序运行起来是一个进程&#xff0c;这个进程对应着一个JVM实例&#xff0c;一个JVM实例对应着一个运行时数据区。而一个运行时数据…

JAVA设计模式-组合模式

目录 1、例子 2、组合模式基本定义 总结&#xff1a; 1、例子 编写程序展示一个学校院系结构&#xff1a;需求是这样&#xff0c;要在一个页面中展示出学校的院系 组成&#xff0c;一个学校有多个学院&#xff0c;一个学院有多个系传统解决方案&#xff1a; 分析&#xff1a;…

一起学solidity写智能合约——整型(uint和int)

前言 整型一般用的比较多&#xff0c;会在各个合约中见到整型的存在&#xff0c;那么这个类型也是学习路上不可或缺的 环境&#xff1a; remix编译器点我跳转 正文 我们在sol中遇得到很多类型为整型的数据&#xff0c;所以我们的sol提供了两种数据类型的整型&#xff1a; …

基于物联网的户外环境检测装置设计

目 录 摘 要 1 Abstract 2 第1章 绪论 4 1.2 选题背景及意义 4 1.2 研究现状 4 1.3本课题的发展趋势和研究可行性 5 1.4研究主要内容 5 第2章 基于物联网的户外环境检测装置设计概述和相关原理 6 2.1 系统的概述 6 2.1.1 总体设计方案 6 2.1.2 总体框图 6 2.2 相关理论 7 2.2.1…

算法优化 | MATLAB实现BO-RF贝叶斯优化随机森林算法

算法优化 | MATLAB实现BO-RF贝叶斯优化随机森林算法 目录 算法优化 | MATLAB实现BO-RF贝叶斯优化随机森林算法效果一览基本介绍模型结构程序设计学习总结参考资料效果一览 基本介绍 针对集成学习参数众多,缺乏高效准确的参数寻优方法的问题,提出了基于贝叶斯优化随机森林方法…

k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

RK3588+AI工业视觉检测设计方案

本文详细介绍了基于Rockchip RK3588芯片的AI边缘计算主板外形、尺寸、技术规格&#xff0c;以及详细的硬件接口设计参考说明&#xff0c;使客户可以快速将RK3588边缘计算主板应用于工业互联网、智慧城市、智慧安防、智慧交通&#xff0c;智慧医疗等人工智能领域的智能终端设备。…