题目
面试官:小夕,做一下这道面试题吧。
小夕:好的,我可以借助辅助栈来实现吗?
面试官:可以的,说一下你的思路吧。
小夕:好的,我图形结合一下,说得清楚些。
第一种辅助栈思路
小夕:
- 维护两个栈,一个输入栈A,一个辅助栈B,辅助栈用于存储当前栈中的最小值
- 每次元素 x 入栈,输入栈 A 直接入栈
- 辅助栈 B 入栈时为空直接入栈,如果 B 不为空,首先取 B 的栈顶元素 min,如果 x 大于min,那么辅助栈 B 继续入栈 min 值,如果 x 小于等于 min,那么辅助栈 B 入栈 x
- 这样辅助栈 B 中每次入栈的元素都是当前栈的最小值
- 这样取栈的 min 值时, 直接返回 B 的栈顶元素即可,时间复杂度是 O(1)
- pop 出栈的话 栈 A 和 栈 B 都出栈,也是时间复杂度是 O(1),push 入栈时间复杂度也是 O(1)
拿题目中[-2,0,-3]
举例。
第一种辅助栈图解思路
动画
代码
Java
class MinStack {
Stack A, B;
/** initialize your data structure here. */
public MinStack() {
A = new Stack<>();
B = new Stack<>();
}
public void push(int x) {
A.push(x);
if (B.empty() || x < B.peek()) { // 辅助栈B为空 或者x小于B的栈顶元素,那么把x入B栈,这样B顶部始终是最小值
B.push(x);
} else {
B.push(B.peek()); // x比B栈顶元素大,那么B栈顶是最小元素,继续B继续入一个栈顶的最小元素。
}
}
public void pop() {
A.pop();
B.pop();
}
public int top() {
return A.peek();
}
public int min() { // B栈顶维护了一个最小值
return B.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.min();
*/
C++
class MinStack {
public:
stack stk,min_stk;//stk为原栈,min_stk为记录每次最小值的栈
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
stk.push(x);
if(min_stk.size()) x=min(x,min_stk.top());//x表示当前的最小值
min_stk.push(x);
}
void pop() {
min_stk.pop();
stk.pop();
}
int top() {
return stk.top();//返回原栈的栈顶
}
int getMin() {
return min_stk.top();//返回每次最小值的栈的栈顶
}
};
Python
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.A = []
self.B=[]
def push(self, x: int) -> None:
self.A.append(x)
if not self.B or self.B[-1]>x:
self.B.append(x)
else:
self.B.append(self.B[-1])
def pop(self) -> None:
self.A.pop();
self.B.pop();
def top(self) -> int:
return self.A[-1]
def min(self) -> int:
return self.B[-1]
Go
type MinStack struct {
elems []int
mins []int
}
/** initialize your data structure here. */
func Constructor() MinStack {
return MinStack{make([]int,0),make([]int,0)}
}
func (this *MinStack) Push(x int) {
this.elems = append(this.elems, x)
if len(this.mins) == 0 || this.GetMin() >= x {
this.mins = append(this.mins, x)
} else {
this.mins = append(this.mins, this.GetMin())
}
}
func (this *MinStack) Pop() {
this.elems = this.elems[:len(this.elems)-1]
this.mins = this.mins[:len(this.mins)-1]
}
func (this *MinStack) Top() int {
return this.elems[len(this.elems) - 1 ]
}
func (this *MinStack) GetMin() int {
return this.mins[len(this.mins)-1]
}
JS
/**
* 解法1 辅助栈
*/
var MinStack = function() {
this.stack1 = [];
this.stack2 = [];
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
this.stack1.push(x);
const stack2Len = this.stack2.length;
if (stack2Len === 0 || this.stack2[stack2Len - 1] >= x) {
this.stack2.push(x);
} else {
this.stack2.push(this.stack2[stack2Len - 1]);
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
if (this.stack1.pop() === this.stack2[this.stack2.length - 1]) {
this.stack2.pop();
}
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
return this.stack1[this.stack1.length - 1];
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.stack2[this.stack2.length - 1];
};
面试官:不错,你这个时间复杂度每个都是O(1),由于借助了辅助栈,空间复杂度是 O(n)。那你能否在你的借助辅助栈的基础上优化一下呢?
小夕: 不是很会啊
第二种辅助栈图解思路
小夕:面试官,想请教一下这个算法该如何优化。。。
面试官:借助辅助栈的思路确实不错,但是辅助栈其实不用每次都压入一个元素,每次只压入当前栈最小值即可。我给你画几张图就很容易记录了~
小夕:好的,辛苦辛苦!!!
图解思路
动画
面试官:题解思路就是这些,代码你写一下,我看你理解到尾没。
小夕:好的。
第二种代码
C
#define max_size 10000
//x_stack存储正常入栈元素,min_stack用来存储入栈时栈中最小的元素
//x_top和min_top分别为栈顶的下标
//min_value用来存储最小值
typedef struct {
int *x_stack;
int *min_stack;
int x_top;
int min_top;
int min_value;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
MinStack *obj = (MinStack*)malloc(sizeof(MinStack));
obj->x_stack = (int*)malloc(sizeof(int) * max_size);
obj->min_stack = (int*)malloc(sizeof(int) * max_size);
obj->min_top = obj->x_top = -1;
obj->min_value = 0;
return obj;
}
void minStackPush(MinStack* obj, int x) {
if(obj->x_top < max_size)
{
if(obj->x_top == -1)
obj->min_value = x;
obj->x_stack[++(obj->x_top)] = x;
if(x < obj->min_value)
obj->min_value = x; //当前元素比min_value小时改变min_value
obj->min_stack[++(obj->min_top)] = obj->min_value;
}
}
void minStackPop(MinStack* obj) {
--(obj->x_top);
--(obj->min_top);
if(obj->min_top != -1)
obj->min_value = obj->min_stack[obj->min_top];//出栈后将min_value变成min_stack的栈顶元素
}
int minStackTop(MinStack* obj) {
return obj->x_stack[obj->x_top];
}
int minStackMin(MinStack* obj) {
return obj->min_stack[obj->min_top];
}
void minStackFree(MinStack* obj) {
free(obj->x_stack);
free(obj->min_stack);
free(obj);
}
/**
* Your MinStack struct will be instantiated and called as such:
* MinStack* obj = minStackCreate();
* minStackPush(obj, x);
* minStackPop(obj);
* int param_3 = minStackTop(obj);
* int param_4 = minStackMin(obj);
* minStackFree(obj);
*/
Java
class MinStack {
Stack A, B;
public MinStack() {
A = new Stack<>();
B = new Stack<>();
}
public void push(int x) {
A.add(x);
if(B.empty() || B.peek() >= x)
B.add(x);
}
public void pop() {
if(A.pop().equals(B.peek()))
B.pop();
}
public int top() {
return A.peek();
}
public int min() {
return B.peek();
}
}
JS
// ac地址:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/
// 原文地址:https://xxoo521.com/2020-01-31-stack-min/
/**
* initialize your data structure here.
*/
var MinStack = function() {
this.dataStack = [];
this.minStack = []; // 辅助栈
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
this.dataStack.push(x);
const length = this.minStack.length;
if (!length) {
this.minStack.push(x);
} else if (x <= this.minStack[length - 1]) {
this.minStack.push(x);
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
const { minStack, dataStack } = this;
if (minStack[minStack.length - 1] === dataStack[dataStack.length - 1]) {
minStack.pop();
}
dataStack.pop();
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
const length = this.dataStack.length;
if (length) {
return this.dataStack[length - 1];
} else {
return null;
}
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
const length = this.minStack.length;
if (!length) return null;
return this.minStack[length - 1];
};
Python
class MinStack:
def __init__(self):
self.stack = []
def push(self, x: int) -> None:
if not self.stack:
self.stack.append((x,x))
else:
min_num = self.min()
if x <= self.min():
self.stack.append((x,x))
else:
self.stack.append((x,min_num))
def pop(self) -> None:
self.stack.pop(-1)
def top(self) -> int:
return self.stack[-1][0]
def min(self) -> int:
return self.stack[-1][1]
第三种使用单栈来实现
面试官:不错不错,你这里借助了辅助栈去实现,这道面试题你想一想有没有不借助辅助栈,只使用一个辅助栈的实现思路?
小夕:只使用一个栈还能实现???
面试官:我提醒你一下,当压栈的值小于栈中最小值时,先把最小值入栈,然后再把需要压栈的值入栈,最后再更新栈中最小值。如果压栈的值大于栈中最小值的时候,直接压栈。
小夕:哦哦哦!!!我好像知道是怎么回事了,我画几张图,辛苦面试官看看小夕理解的对不对。
图解思路
动画
第三种使用单栈来实现代码
Java
class MinStack {//push方法可能会加入很多min
int min = Integer.MAX_VALUE;
Stack stack = new Stack<>();
public void push(int x) {
//如果加入的值小于最小值,要更新最小值
if (x <= min) {
stack.push(min);
min = x;
}
stack.push(x);
}
public void pop() {
//如果把最小值出栈了,就更新最小值
if (stack.pop() == min)
min = stack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return min;
}
}
C++
class MinStack {
public:
int min=0x3f3f3f3f;
stack stk;//stk栈
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
//如果加入的值小于最小值,要更新最小值
if (x <= min) {
stk.push(min);
min = x;
}
stk.push(x);
}
void pop() {
//如果把最小值出栈了,就更新最小值
int p = stk.top();
stk.pop();
if (p == min)
{
min = stk.top();
stk.pop();
}
}
int top() {
return stk.top();//返栈的栈顶
}
int getMin() {
return min;//返回栈的栈顶
}
};
Python
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.min_value =float('inf')
self.stack = []
def push(self, x: int) -> None:
if x<=self.min_value:
self.stack.append(self.min_value)
self.min_value = x
self.stack.append(x);
def pop(self) -> None:
if self.stack.pop()==self.min_value:
self.min_value = self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return self.min_value
JS
/**
* 解法3 单调栈
*/
var MinStack = function() {
this.stack = [];
this.min = Number.MAX_SAFE_INTEGER;
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
if (x < this.min) {
this.min = x;
}
this.stack.push(x);
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
if (!this.stack.length) return;
const curValue = this.stack.pop();
if (this.min === curValue) {
this.min = Math.min(...this.stack);
}
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
const len = this.stack.length;
if (!len) return Infinity;
return this.stack[len - 1];
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.min;
};
Go
// 单个栈
type MinStack struct {
stack []int;
}
/** initialize your data structure here. */
func Constructor() MinStack {
return MinStack{make([]int,0)}
}
func (this *MinStack) Push(x int) {
if len(this.stack)==0 || this.GetMin()>x {
this.stack = append(this.stack,x,x)
}else{
this.stack = append(this.stack,this.GetMin(),x)
}
}
func (this *MinStack) Pop() {
this.stack = this.stack[:len(this.stack)-2]
}
func (this *MinStack) Top() int {
return this.stack[len(this.stack)-1]
}
func (this *MinStack) GetMin() int {
return this.stack[len(this.stack)-2]
}
自定义链表节点
面试官:不错,就是这个意思,代码也写得不错,还会这么多语言,厉害了。
面试官:其实这道题我之前还见过一个自己定义链表的数据结构的解法。
小夕:啊,面试官真是见多识广
面试官:你只需要定义一个链表节点,这个链表节点的定义我给你定义出来,你根据这个结构就知道怎么做了!
小夕:谢谢面试官!我按照这个节点定义说一下我的思路。
链表节点定义
class ListNode {
public int val;
public int min;//最小值
public ListNode next;
public ListNode(int val, int min, ListNode next) {
this.val = val;
this.min = min;
this.next = next;
}
}
图解思路
动画
代码
Java
class MinStack {
//链表头,相当于栈顶
private ListNode head;
//压栈,需要判断栈是否为空
public void push(int x) {
if (empty())
head = new ListNode(x, x, null);
else
head = new ListNode(x, Math.min(x, head.min), head);
}
//出栈,相当于把链表头删除
public void pop() {
if (empty())
throw new IllegalStateException("栈为空……");
head = head.next;
}
//栈顶的值也就是链表头的值
public int top() {
if (empty())
throw new IllegalStateException("栈为空……");
return head.val;
}
//链表中头结点保存的是整个链表最小的值,所以返回head.min也就是
//相当于返回栈中最小的值
public int min() {
if (empty())
throw new IllegalStateException("栈为空……");
return head.min;
}
//判断栈是否为空
private boolean empty() {
return head == null;
}
}
class ListNode {
public int val;
public int min;//最小值
public ListNode next;
public ListNode(int val, int min, ListNode next) {
this.val = val;
this.min = min;
this.next = next;
}
}
Python
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.head = None
def push(self, x: int) -> None:
if not self.head:
self.head = ListNode(x,x,None)
else:
p = ListNode(x,min(x,self.head.min_val),self.head)
self.head = p
def pop(self) -> None:
self.head = self.head.next
def top(self) -> int:
return self.head.val
def min(self) -> int:
return self.head.min_val
class ListNode:
def __init__(self,x=None,min_val=None,next=None):
self.val = x
self.min_val = min_val
self.next = next
JS
/**
* 解法2 链表
*/
class LinkNode {
constructor(val, min) {
this.val = val;
this.min = min;
this.next = null;
}
}
var MinStack = function () {
this.head = null;
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
if (this.head === null) {
this.head = new LinkNode(x, x);
} else {
const temp = new LinkNode(x, Math.min(x, this.head.min));
[temp.next, this.head] = [this.head, temp];
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
if (this.head !== null) {
this.head = this.head.next;
}
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
if (this.head !== null) {
return this.head.val;
}
return Infinity;
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
if (this.head !== null) {
return this.head.min;
}
return -Infinity;
};
小夕:面试官,你看我说得对不对。
面试官:不错不错,就是这个样子。
小夕:谢谢面试官,面试官你这么厉害