
🏠个人主页:黎雁
🎬作者简介:C/C++/JAVA后端开发学习者
❄️个人专栏:C语言、数据结构(C语言)、EasyX、游戏、规划、程序人生
✨ 从来绝巘须孤往,万里同尘即玉京

文章目录
- 栈与队列实战通关:3道经典OJ题深度解析✨
-
- 文章摘要
- 一、知识回顾:栈与队列核心解题思路
- [二、实战第一题:有效的括号(LeetCode 20)🔥](#二、实战第一题:有效的括号(LeetCode 20)🔥)
- [三、实战第二题:用队列实现栈(LeetCode 225)🔄](#三、实战第二题:用队列实现栈(LeetCode 225)🔄)
- [四、实战第三题:用栈实现队列(LeetCode 232)🔄](#四、实战第三题:用栈实现队列(LeetCode 232)🔄)
- 五、核心解题技巧总结🎯
- 六、写在最后
栈与队列实战通关:3道经典OJ题深度解析✨
你好!欢迎来到线性表系列栈与队列篇的终篇内容~
在前两篇中,我们已经吃透了栈和队列的核心概念与底层实现,从"后进先出"的栈到"先进先出"的队列,完成了理论基础的搭建。但数据结构的学习最终要落地到实战------今天我们就聚焦LeetCode高频OJ题,用3道经典题目带你打通栈与队列的解题思路,把理论转化为真正的解题能力!💪
文章摘要
本文为线性表系列栈与队列篇终篇实战内容,聚焦3道高频OJ题深度解析。以有效的括号、用队列实现栈、用栈实现队列为核心,拆解每道题的解题思路,提供完整可运行的代码实现,详解栈与队列的特性适配、边界条件处理及报错调试技巧。从基础应用到结构转换,全方位锻炼栈与队列的灵活运用能力,零基础也能通关经典算法题。
阅读时长 :约25分钟
阅读建议:
- 初学者:先理解解题思路,再逐行分析代码逻辑
- 刷题备考者:重点掌握"结构转换"类题目的核心思想
- 面试冲刺者:牢记括号匹配的解题模板,可直接复用
- 查漏补缺者:聚焦代码中的报错处理和边界判断细节
一、知识回顾:栈与队列核心解题思路
在刷OJ题之前,先梳理栈与队列的核心解题技巧:
| 数据结构 | 核心特性 | 典型应用场景 | 解题关键 |
|---|---|---|---|
| 栈 | 后进先出 | 括号匹配、表达式求值、逆序处理 | 左入栈、右匹配,利用栈顶做对比 |
| 队列 | 先进先出 | 层序遍历、任务排队、结构转换 | 双队列/双栈联动,实现特性反转 |
核心原则:用栈处理"逆序"问题,用队列处理"顺序"问题,二者联动可实现特性互转!
二、实战第一题:有效的括号(LeetCode 20)🔥
题目描述
给定只包含 '('、')'、'['、']'、'{'、'}' 的字符串 s,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合
- 左括号必须以正确的顺序闭合
示例:
- 输入:
s = "()"→ 输出:true - 输入:
s = "([)]"→ 输出:false - 输入:
s = "{()}"→ 输出:true
解题思路(栈的经典应用)
✅ 核心逻辑:左括号入栈,右括号出栈匹配
- 遍历字符串,遇到左括号(
(/[/{)直接入栈 - 遇到右括号(
)/]/}):- 若栈为空 → 无左括号匹配,直接返回
false - 弹出栈顶元素,判断是否与当前右括号匹配
- 不匹配则返回
false,匹配则继续遍历
- 若栈为空 → 无左括号匹配,直接返回
- 遍历结束后,若栈为空 → 所有括号匹配成功;否则返回
false
完整代码实现
c
#include "stack.h" // 引入之前实现的栈头文件
bool isValid(char* s)
{
ST st;
StackInit(&st); // 初始化栈
while (*s != '\0')
{
// 左括号入栈
if (*s == '(' || *s == '[' || *s == '{')
{
StackPush(&st, *s);
s++;
}
// 右括号匹配
else
{
// 栈空但遇到右括号 → 无效
if (StackEmpty(&st))
{
StackDestroy(&st);
return false;
}
char top = StackTop(&st);
StackPop(&st);
// 判断是否匹配
if ((*s == ')' && top != '(') ||
(*s == ']' && top != '[') ||
(*s == '}' && top != '{'))
{
StackDestroy(&st);
return false;
}
s++;
}
}
// 遍历结束后栈必须为空(避免左括号多余)
bool ret = StackEmpty(&st);
StackDestroy(&st); // 必须销毁栈,避免内存泄漏
return ret;
}
易错点&调试技巧
- ❌ 忘记销毁栈:会导致内存泄漏,OJ可能不报错但工程中必出问题
- ❌ 忽略"栈空遇右括号":比如输入
")(",需提前判空 - ❌ 遍历结束后未检查栈空:比如输入
"({",左括号多余需返回false - 📝 调试技巧:遇到报错先看测试用例,用纸笔模拟栈的入栈/出栈过程
三、实战第二题:用队列实现栈(LeetCode 225)🔄
题目描述
仅使用两个队列实现一个后进先出(LIFO)的栈,支持栈的push、pop、top、empty操作。
解题思路(队列转栈)
✅ 核心逻辑:双队列联动,保留最后一个元素实现后进先出
- 准备两个队列
q1、q2,始终保持一个队列为空 - 入栈:往非空队列中插入元素(都空则随便选一个)
- 出栈:将非空队列的元素依次导入空队列,仅保留最后一个元素,弹出该元素
- 获取栈顶:直接取非空队列的队尾元素
完整代码实现
c
#include "queue.h" // 引入之前实现的队列头文件
// 定义栈结构(包含两个队列)
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
// 创建栈
MyStack* myStackCreate()
{
MyStack* ps = (MyStack*)malloc(sizeof(MyStack));
if (ps == NULL)
{
perror("malloc fail");
exit(1);
}
QueueInit(&ps->q1);
QueueInit(&ps->q2);
return ps;
}
// 入栈
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);
}
四、实战第三题:用栈实现队列(LeetCode 232)🔄
题目描述
仅使用两个栈实现一个先进先出(FIFO)的队列,支持队列的push、pop、peek、empty操作。
解题思路(栈转队列)
✅ 核心逻辑:双栈分工,入栈存数据,出栈做反转
- 准备两个栈
pushST(入队专用)、popST(出队专用) - 入队:直接往
pushST中压栈 - 出队:若
popST为空,将pushST的所有元素导入popST(实现反转),再弹出popST栈顶 - 获取队头:逻辑同出队,仅取栈顶不弹出
完整代码实现
c
// 栈的基础实现(复用之前的栈结构)
typedef int STData;
typedef struct Stack
{
STData* a;
int top;
int capacity;
}ST;
void STInit(ST* ps)
{
assert(ps);
ps->a = (STData*)malloc(sizeof(STData)*4);
if (ps->a == NULL) { perror("malloc fail"); exit(1); }
ps->capacity = 4;
ps->top = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void STPush(ST* ps, STData x)
{
assert(ps);
if (ps->top == ps->capacity)
{
STData* tmp = (STData*)realloc(ps->a, sizeof(STData)*ps->capacity*2);
if (tmp == NULL) { perror("realloc fail"); exit(1); }
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top++] = x;
}
void STPop(ST* ps) { assert(ps); assert(!(ps->top == 0)); ps->top--; }
STData STTop(ST* ps) { assert(ps); assert(!(ps->top == 0)); return ps->a[ps->top-1]; }
bool STEmpty(ST* ps) { assert(ps); return ps->top == 0; }
// 队列结构定义(包含两个栈)
typedef struct
{
ST pushst; // 入队栈
ST popst; // 出队栈
} MyQueue;
// 创建队列
MyQueue* myQueueCreate()
{
MyQueue *q = (MyQueue*)malloc(sizeof(MyQueue));
if (q == NULL) { perror("malloc fail"); exit(1); }
STInit(&q->pushst);
STInit(&q->popst);
return q;
}
// 入队
void myQueuePush(MyQueue* obj, int x)
{
STPush(&obj->pushst, x); // 只管往pushst插入
}
// 出队
int myQueuePop(MyQueue* obj)
{
// popst为空时,导入pushst的所有元素
if (STEmpty(&obj->popst))
{
while (!STEmpty(&obj->pushst))
{
STPush(&obj->popst, STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
int top = STTop(&obj->popst);
STPop(&obj->popst);
return top;
}
// 获取队头
int myQueuePeek(MyQueue* obj)
{
if (STEmpty(&obj->popst))
{
while (!STEmpty(&obj->pushst))
{
STPush(&obj->popst, STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);
}
// 判断队列空
bool myQueueEmpty(MyQueue* obj)
{
return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
}
// 销毁队列
void myQueueFree(MyQueue* obj)
{
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
五、核心解题技巧总结🎯
- 括号匹配:栈是最优解,记住"左入右匹配"的模板,可直接应对所有括号类题目
- 结构转换 :
- 队列实现栈:双队列"留最后一个元素"
- 栈实现队列:双栈"入栈存、出栈转"
- 内存管理:OJ题也要注意销毁栈/队列,避免内存泄漏(工程中必现问题)
- 边界处理:所有操作前先判空,是避免空指针错误的关键
六、写在最后
恭喜你!栈与队列篇至此圆满结束🎉~
从栈和队列的核心概念,到底层工程化实现,再到经典OJ题实战,你已经完成了"理论→实现→应用"的完整闭环:
- 掌握了栈"后进先出"、队列"先进先出"的核心特性
- 能独立实现数组版栈、链表版队列的完整代码
- 会用栈和队列解决括号匹配、结构转换等经典问题
栈和队列是数据结构的"入门基石",后续的二叉树、图、算法优化都离不开它们。建议你多敲几遍代码,吃透每一道题的解题思路------编程的核心,永远是"理解+实践"!
下一个系列,我们将进入二叉树的世界,开启更有趣的学习之旅~😜
点赞+收藏+关注,跟着系列内容一步步吃透数据结构!你的支持是我创作的最大动力~👍