⭐算法入门⭐《栈 - 单调栈》简单01 —— LeetCode 155. 最小栈
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了⭐算法入门⭐《栈 - 单调栈》简单01 —— LeetCode 155. 最小栈相关的知识,希望对你有一定的参考价值。
🙉饭不食,水不饮,题必须刷🙉
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
LeetCode 太难?先看简单题! 🧡《C语言入门100例》🧡
数据结构难?不存在的! 🌳《画解数据结构》🌳
LeetCode 太简单?算法学起来! 🌌《夜深人静写算法》🌌
一、题目
1、题目描述
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x)
—— 将元素 x 推入栈中。
pop()
—— 删除栈顶的元素。
top()
—— 获取栈顶元素。
getMin()
—— 检索栈中的最小元素。
样例输入:["MinStack","push","push","push","getMin","pop","top","getMin"]
样例输出:[null,null,null,null,-3,null,0,-2]
2、基础框架
- C语言 版本给出的基础框架代码如下:
typedef struct {
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
}
void minStackPush(MinStack* obj, int val) {
}
void minStackPop(MinStack* obj) {
}
int minStackTop(MinStack* obj) {
}
int minStackGetMin(MinStack* obj) {
}
void minStackFree(MinStack* obj) {
}
/**
* Your MinStack struct will be instantiated and called as such:
* MinStack* obj = minStackCreate();
* minStackPush(obj, val);
* minStackPop(obj);
* int param_3 = minStackTop(obj);
* int param_4 = minStackGetMin(obj);
* minStackFree(obj);
*/
- 要求支持一般的栈操作以外,还需要支持一种操作,就是
O
(
1
)
O(1)
O(1) 的时间获取最小值。
3、原题链接
( 1 ) (1) (1) LeetCode 155. 最小栈
( 2 ) (2) (2) 面试题 03.02. 栈的最小值
( 3 ) (3) (3) 剑指 Offer 30. 包含min函数的栈
二、解题报告
1、思路分析
1)栈的数据
- 每个栈的元素用一个结构体表示,除了存储数据本身,还需要存储一个全局 ID,利用这个 ID 可以用于判断两个 栈数据 是否相等。
struct Node {
int idx;
int val;
};
2)数据结构设计
- 对于这个最小栈,设计的时候需要设计两个栈,一个是单调栈,一个是正常的栈,如下:
typedef struct {
struct Stack normal;
struct Stack min;
int idx;
} MinStack;
3)算法思路
- 利用两个栈,一个是单调栈,一个是正常栈;
- 正常栈处理所有和 最小值 无关的操作,取 最小值 这个操作就是取的 单调栈 的栈顶;
- 考虑进栈元素 1、3。 基于 后进先出 这个特点,1 这个元素在栈中的生命周期肯定会被 3 长,且 1 更小,所以,1 比 3 更优,那么基于单调性,如果 1 和 3 依次进入单调栈,3 应该被弹出来(或者说 3 根本就不用进单调栈)。于是,我们发现单调栈的性质,从 栈低 到 栈顶 不可能是单调递增的,所以它就是单调递减的。
- 再考虑进栈元素1、0, 1 的声明周期虽然比 0 长,但是 0 的值比 1 小,在 0 没有弹栈之前,最小值应该是 0;弹栈之后,最小值才是 1,所以两者都应该被栈保留下来,如下图所示:
- 于是,思路就清晰了,单调栈对于每一步操作,始终维护一个单调递减的栈即可。
- 有关单调栈更多的内容,可以看以下这篇文章:夜深人静写算法(十一)- 单调栈。
4)接口实现
- 实际接口实现,请参见下文的代码注释。
- 有关 栈 的实现,可以参见以下文章:《画解数据结构》栈。
2、时间复杂度
- 由于每个括号最多入栈一次,出栈一次。
- 所以时间复杂度:每一步操作的均摊时间复杂度为 O ( 1 ) O(1) O(1)
3、代码详解
/************************************* 栈的顺序表实现 *************************************/
#define DataType struct Node
#define maxn 100010
struct Node {
int idx;
int val;
};
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 normal;
struct Stack min;
int idx;
} MinStack;
/* (1) */
MinStack* minStackCreate() {
MinStack *ms = ( MinStack *)malloc( sizeof(MinStack) );
StackClear( &ms->normal );
StackClear( &ms->min );
ms->idx = 0;
return ms;
}
/* (2) */
void minStackPush(MinStack* obj, int val) {
struct Node nd;
nd.idx = ++obj->idx;
nd.val = val;
if( !StackIsEmpty(&obj->min) ) {
if( StackGetTop(&obj->min).val > nd.val ) {
StackPushStack( &obj->min, nd );
}
} else {
StackPushStack( &obj->min, nd );
}
StackPushStack( &obj->normal, nd);
}
/* (3) */
void minStackPop(MinStack* obj) {
struct Node nd = StackGetTop( &obj->normal );
struct Node ndmin = StackGetTop( &obj->min );
if(nd.idx == ndmin.idx)
StackPopStack(&obj->min);
StackPopStack(&obj->normal);
}
/* (4) */
int minStackTop(MinStack* obj) {
return StackGetTop( &obj->normal ).val;
}
/* (5) */
int minStackGetMin(MinStack* obj) {
return StackGetTop( &obj->min ).val;
}
void minStackFree(MinStack* obj) {
free(obj);
}
/**
* Your MinStack struct will be instantiated and called as such:
* MinStack* obj = minStackCreate();
* minStackPush(obj, val);
* minStackPop(obj);
* int param_3 = minStackTop(obj);
* int param_4 = minStackGetMin(obj);
* minStackFree(obj);
*/
-
(
1
)
(1)
(1)
minStackCreate
:利用malloc
申请空间后返回内存首地址作为 最小栈 的基地址; -
(
2
)
(2)
(2)
minStackPush
:确保 push 操作后,单调栈 是单调递减的,所以如果它比 栈顶元素大 就没必要入栈了;而 正常栈 正常 push 即可; -
(
3
)
(3)
(3)
minStackPop
:正常栈 的元素是一定会 pop 的,如果 正常栈栈顶元素 和 单调栈栈顶元素 相同,则单调栈 pop;这里相同判定不能判定数值,而是要用之前定义的 全局ID。 -
(
4
)
(4)
(4)
minStackTop
:取栈顶,就是取 正常栈栈顶元素; -
(
5
)
(5)
(5)
minStackGetMin
:取最小值,就是取 单调栈栈顶元素;
三、本题小知识
我们在设计数据结构的时候,对外提供的可能是一种数据结构,但是内部实现我们往往会对常用数据结构进行组合。即对于外部来说,只需要暴露接口即可,它们并不知道内部是如何实现的,这样就很好的将要做的事情进行了抽象。
以上是关于⭐算法入门⭐《栈 - 单调栈》简单01 —— LeetCode 155. 最小栈的主要内容,如果未能解决你的问题,请参考以下文章