刷爆leetcode第六期

简介: 刷爆leetcode第六期

题目一 用队列实现栈

请你仅使用两个队列实现一个后入先出(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(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

 

我们先来分析下题目

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

我们来看第一个Push操作

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

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

来看图

有思路了

图上是两个队列

我们假设 注意啊 是假设

第一行的图 它就是一个栈

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

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

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

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

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

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

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

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


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


 

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

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

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


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


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


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


也就是两个步骤


1.保持一个队列为空,一个队列存数据


2.出栈,把前面的数据倒入空队列


接下来我们来实现代码


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

第一步 定义结构体

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

既然是两个队列的实现的

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

仔细一想好像可行

我们来试试

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

画个图方便大家理解

三个结构体的关系一目了然

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

MyStack* myStackCreate() {
     MyStack*pst = ( MyStack*)malloc(sizeof( MyStack));
     if(pst==NULL)
     {
        perror("malloc fail");
        return NULL;
     }
     QueueInit(&pst->q1);
     QueueInit(&pst->q2);
     return pst;
}

第三步 插入数据

这里要判断队列是否为空,不为空就插入数据,两个都为空就随机一个队列插入数据

看代码:

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

第四步 删除数据

这是最难的部分,需要我们倒数据

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

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

代码整体表现不变

int myStackPop(MyStack* obj) {
    Queue*emptyQ = &obj->q1;
    Queue*nonemptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        emptyQ = &obj->q2;
        nonemptyQ=&obj->q1;
    }
    //倒数据
    while(QueueSize(nonemptyQ)>1)
    {
        QueuePush(emptyQ,QueueFront(nonemptyQ));
        QueuePop(nonemptyQ);
    }
    //记录删除值 删掉
    int top = QueueFront(nonemptyQ);
    QueuePop(nonemptyQ);
    return top;
}

第五步 返回头的值

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

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

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

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

第六步 判空

这步就很简单,只需要判断1和2是否都为空,都为空即空

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

第七步 释放

这里要依次释放销毁,类似套娃

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

源码

typedef int QDateType;
typedef struct QueueNode
{
  struct QueueNode* next;
  QDateType date;
}QNode;
typedef struct Queue
{
  QNode* head;
  QNode* tail;
  int size;
}Queue;
//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestroy(Queue* pq);
//队进
void QueuePush(Queue* pq, QDateType x);
//队出
void QueuePop(Queue* pq);
//判断为空
bool QueueEmpty(Queue* pq);
//个数
int QueueSize(Queue* pq);
//队尾
QDateType QueueBack(Queue* pq);
//对头
QDateType QueueFront(Queue* pq);
//初始化
void QueueInit(Queue* pq)
{
  assert(pq);
  pq->head = pq->tail = NULL;
  pq->size = 0;
}
//销毁
void QueueDestroy(Queue* pq)
{
  assert(pq);
  //两个结构体依次销毁 先销毁QNode
  QNode* cur = pq->head;
  while (cur)
  {
    QNode* next = cur->next;
    free(cur);
    cur = next;
  }
  //再置空Queue
  pq->head = pq->tail = NULL;
  pq->size = 0;
}
//队进
void QueuePush(Queue* pq, QDateType x)
{
  assert(pq);
  //开辟新节点
  QNode* newnode = (QNode*)malloc(sizeof(QNode));
  if (newnode == NULL)
  {
    perror("malloc fail");
    return;
  }
  //赋值
  newnode->next = NULL;
  newnode->date = x;
  //判断是否为空
  if (pq->head == NULL)
  {
    pq->head = pq->tail = newnode;
  }
  else
  {
    pq->tail->next = newnode;
    pq->tail = newnode;
  }
  //个数要++
  pq->size++;
}
//队出
void QueuePop(Queue* pq)
{
  assert(pq);
  assert(pq->head!=NULL);
  //只有一个节点
  if (pq->head->next == NULL)
  {
    free(pq->head);
    pq->head = pq->tail = NULL;
  }
  else
  {
    //保存下一位
    QNode* next = pq->head->next;
    free(pq->head);
    pq->head = next;//迭代
  }
  //个数要--
  pq->size--;
}
//判断为空
bool QueueEmpty(Queue* pq)
{
  assert(pq);
 
  return pq->size == 0;
}
//大小
int QueueSize(Queue* pq)
{
  assert(pq);
 
  return pq->size;
}
//队尾
QDateType QueueBack(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
 
  return pq->tail->date;
}
//对头
QDateType QueueFront(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
 
  return pq->head->date;
}
 
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;
 
 
MyStack* myStackCreate() {
     MyStack*pst = ( MyStack*)malloc(sizeof( MyStack));
     if(pst==NULL)
     {
        perror("malloc fail");
        return NULL;
     }
     QueueInit(&pst->q1);
     QueueInit(&pst->q2);
     return pst;
}
 
void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }else{
        QueuePush(&obj->q2,x);
    }
}
 
int myStackPop(MyStack* obj) {
    Queue*emptyQ = &obj->q1;
    Queue*nonemptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        emptyQ = &obj->q2;
        nonemptyQ=&obj->q1;
    }
    //倒数据
    while(QueueSize(nonemptyQ)>1)
    {
        QueuePush(emptyQ,QueueFront(nonemptyQ));
        QueuePop(nonemptyQ);
    }
    //记录删除值 删掉
    int top = QueueFront(nonemptyQ);
    QueuePop(nonemptyQ);
    return top;
}
 
int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }else{
        return QueueBack(&obj->q2);
    }
}
 
bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
 
void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}


以上便是本文所有内容了,如有错误请各位大佬不吝赐教,感谢留言

目录
相关文章
|
安全 网络安全 PHP
网络安全-RCE(远程命令执行)漏洞原理、攻击与防御
网络安全-RCE(远程命令执行)漏洞原理、攻击与防御
1825 0
网络安全-RCE(远程命令执行)漏洞原理、攻击与防御
|
弹性计算 Serverless 调度
面向Workload级别的灵活可配置Serverless弹性解决方案
Serverless作为云计算的延伸,能提供按需弹性伸缩的能力,让开发者无需关心具体资源部署,优化资源使用,因而被众多云厂商采用本文将介绍四种资源可配置插件,探讨它们的核心能力、技术原理,以及在实际应用中的优劣势。
|
9月前
|
人工智能 搜索推荐 小程序
AI题库考试系统
本平台融合AI智能技术,打造高效课程试题库,支持PC、手机在线刷题,提供智能出题、自动解析、错题回顾、背题模式等功能,覆盖章节练习、笔记收藏、多端同步,助力学员精准提分,全面提升学习效率。
|
存储 安全 API
阿里云先知安全沙龙(上海站) ——红队武器开发之基于合法服务的隐蔽C2
C2(命令与控制)是攻击者远程控制受感染主机的技术。通过合法服务平台(如Slack、Telegram等)的API,攻击者可以隐蔽地传输指令和数据,避免被传统检测机制发现。合法服务具备以下优势: 1. **隐蔽性强**:流量隐藏在正常通信中,难以被检测。 2. **开发成本低**:无需自行开发服务端,减少工作量。 3. **抗封禁能力**:合法域名/IP不易被封禁,威胁情报不会标黑。 4. **团队协作**:天然支持多成员协同作战。 示例包括SaaiwC组织利用Telegram和APT29组织利用Zulip平台进行数据传输和控制。
|
弹性计算 安全 Linux
操作系统智能助手OS Copilot体验评测
从了解到部署实践全方位带你体验操作系统智能助手OS Copilot的优与劣。
17110 8
操作系统智能助手OS Copilot体验评测
|
存储 安全 Linux
Linux passwd命令:守护账户安全的密钥
`passwd`命令是Linux中管理用户密码的关键工具,确保数据安全。它用于更改密码,采用加密存储,并有锁定/解锁账号、设置密码策略等功能。参数如`-d`删除密码,`-l`锁定账号,`-u`解锁。最佳实践包括定期更改复杂密码,保护root密码,谨慎使用无密码选项。了解和正确使用passwd是保障系统安全的重要步骤。
|
API Python
Blender导出带透明贴图的gltf模型
Blender导出带透明贴图的gltf模型
915 0
Blender导出带透明贴图的gltf模型
|
机器学习/深度学习 数据可视化 Python
如何可视化神经网络的神经元节点之间的连接?附有Python预处理代码
该博客展示了如何通过Python预处理神经网络权重矩阵并将其导出为表格,然后使用Chiplot网站来可视化神经网络的神经元节点之间的连接。
364 0
如何可视化神经网络的神经元节点之间的连接?附有Python预处理代码
|
Kubernetes Linux 网络安全
kubeadm安装k8s
该文档提供了一套在CentOS 7.6上安装Docker和Kubernetes(kubeadm)的详细步骤,包括安装系统必备软件、关闭防火墙和SELinux、禁用swap、开启IP转发、设置内核参数、配置Docker源和加速器、安装指定版本Docker、启动Docker、设置kubelet开机启动、安装kubelet、kubeadm、kubectl、下载和配置Kubernetes镜像、初始化kubeadm、创建kubeconfig文件、获取节点加入集群命令、下载Calico YAML文件以及安装Calico。这些步骤不仅适用于v1.19.14,也适用于更高版本。
521 1
|
XML Linux 应用服务中间件
centos7搭建minio并实现分享路径为域名路径
centos7搭建minio并实现分享路径为域名路径
1533 0