⭐算法入门⭐《栈 和 队列》简单01 —— LeetCode 232. 用栈实现队列

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了⭐算法入门⭐《栈 和 队列》简单01 —— LeetCode 232. 用栈实现队列相关的知识,希望对你有一定的参考价值。

🙉饭不食,水不饮,题必须刷🙉

C语言免费动漫教程,和我一起打卡!
🌞《光天化日学C语言》🌞

LeetCode 太难?先看简单题!
🧡《C语言入门100例》🧡

数据结构难?不存在的!
🌳《画解数据结构》🌳

LeetCode 太简单?算法学起来!
🌌《夜深人静写算法》🌌

一、题目

1、题目描述

  仅使用两个栈实现 先入先出 队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现 MyQueue 类:
  void push(int x)将元素 x 推到队列的末尾
  int pop()从队列的开头移除并返回元素
  int peek()返回队列开头的元素
  boolean empty()如果队列为空,返回 true ;否则,返回 false
说明:
  只能使用标准的栈操作。实现每个操作均摊时间复杂度为 O ( 1 ) O(1) O(1) 的队列?换句话说,执行 n n n 个操作的总时间复杂度为 O ( n ) O(n) O(n),即使其中一个操作可能花费较长时间。
  样例输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []]
  样例输出: [null, null, null, 1, 1, false]

2、基础框架

  • C语言版本 给出的基础框架代码如下:
typedef struct {
} MyQueue;

/** Initialize your data structure here. */
MyQueue* myQueueCreate() {
}

/** Push element x to the back of queue. */
void myQueuePush(MyQueue* obj, int x) {
}

/** Removes the element from in front of queue and returns that element. */
int myQueuePop(MyQueue* obj) {
}

/** Get the front element. */
int myQueuePeek(MyQueue* obj) {
}

/** Returns whether the queue is empty. */
bool myQueueEmpty(MyQueue* obj) {
}

void myQueueFree(MyQueue* obj) {
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

3、原题链接

( 1 ) (1) (1) LeetCode 232. 用栈实现队列
( 2 ) (2) (2) 剑指 Offer 09. 用两个栈实现队列
( 3 ) (3) (3) 面试题 03.04. 化栈为队

二、解题报告

1、思路分析

  • 考虑用两个栈,一个用来 push;一个用来 pop
  • push 操作的时候,只需要无脑 入栈 即可;
  • pop 操作时,先要判断栈中是否有元素,如果没有,则一次性将 push 栈中的元素都 pop 出来,并且 入栈到 pop 栈中,再执行 pop 操作;
  • 有关 的实现,可以参见以下文章:《画解数据结构》栈

2、时间复杂度

  • 任何一个元素只会在每个栈中入栈和出栈各一次,总的时间复杂度为 O ( n ) O(n) O(n)。均摊下来每次的操作就是 O ( 1 ) O(1) O(1) 的。

3、代码详解

/************************************* 栈的顺序表实现 *************************************/
#define DataType int
#define maxn 100010

struct Stack {
    DataType data[maxn];
    int top;
};

void StackClear(struct Stack* stk) {
    stk->top = 0;
}
void StackPushStack(struct Stack *stk, DataType dt) {
    stk->data[ stk->top++ ] = dt;
}
void StackPopStack(struct Stack* stk) {
    --stk->top;
}

DataType StackGetTop(struct Stack* stk) {
    return stk->data[ stk->top - 1 ];
}
int StackGetSize(struct Stack* stk) {
    return stk->top;
}
bool StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);
}
/************************************* 栈的顺序表实现 *************************************/

typedef struct {
    struct Stack push;                             // (1)
    struct Stack pop;                              // (2)
} MyQueue;

/** (3) */
MyQueue* myQueueCreate() {
    MyQueue *q = (MyQueue *)malloc(sizeof(MyQueue));
    StackClear(& (q->push) );
    StackClear(& (q->pop) );
    return q;
}

/** (4) */
void myQueuePush(MyQueue* obj, int x) {
    StackPushStack( & obj->push, x );
}

/** (5) */
void myQueueCheckPop(MyQueue* obj) {
    int val;
    if( StackIsEmpty( & obj->pop ) ) {
        while( !StackIsEmpty(& obj->push ) ) {
            val = StackGetTop( &obj->push );
            StackPushStack( &obj->pop, val ); 
            StackPopStack( &obj->push );       
        }
    }
}

/** (6) */
int myQueuePop(MyQueue* obj) {
    int ret;
    myQueueCheckPop(obj);
    ret = StackGetTop( & obj->pop );
    StackPopStack( &obj->pop );
    return ret;
}

/** (7) */
int myQueuePeek(MyQueue* obj) {
    int ret;
    myQueueCheckPop(obj);
    ret = StackGetTop( & obj->pop );
    return ret;
}

/** (8) */
bool myQueueEmpty(MyQueue* obj) {
    return StackIsEmpty( &obj->push ) && StackIsEmpty( &obj->pop );
}

void myQueueFree(MyQueue* obj) {
    free(obj);
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/
  • ( 1 ) (1) (1) 入队操作时 入栈push栈 中;
  • ( 2 ) (2) (2) 出队操作时 从 pop栈 进行 弹栈
  • ( 3 ) (3) (3) myQueueCreate:申请内存,对两个栈进行初始化;
  • ( 4 ) (4) (4) myQueuePush:将元素 入栈push栈 中;
  • ( 5 ) (5) (5) myQueueCheckPop:将 push栈 中的数据 弹栈,再入栈pop栈 中;
  • ( 6 ) (6) (6) myQueuePop:先执行myQueueCheckPop,再从 pop栈 进行 弹栈
  • ( 7 ) (7) (7) myQueuePeek:先执行myQueueCheckPop,再从 pop栈栈顶元素 返回;
  • ( 8 ) (8) (8) 两个栈均为空才认为这个队列为空;

三、本题小知识

   我们在考虑问题的时候,往往可以将一个问题和另一个问题联系起来,将另一个子问题抽成一个子函数,这样就可以屏蔽子函数的实现细节。


以上是关于⭐算法入门⭐《栈 和 队列》简单01 —— LeetCode 232. 用栈实现队列的主要内容,如果未能解决你的问题,请参考以下文章

⭐算法入门⭐《栈 和 队列》简单02 —— LeetCode 225. 用队列实现栈

⭐算法入门⭐《栈 - 单调栈》简单01 —— LeetCode 155. 最小栈

⭐算法入门⭐《栈》简单01 —— LeetCode 20. 有效的括号

⭐算法入门⭐《队列》简单01 —— LeetCode 933. 最近的请求次数

⭐算法入门⭐《栈》简单04 —— LeetCode 682. 棒球比赛

⭐算法入门⭐《栈》简单02 —— LeetCode 234. 回文链表