算法学习 - 最小栈的实现O(1)时间
来源:程序员人生 发布时间:2014-12-17 08:41:24 阅读次数:2562次
最小栈
最小栈其实和栈没有甚么区分的,唯1的区分在于最小栈是可以在O(1)时间内得到当前的栈空间里,最小的值是多少。
最小栈的操作
最小栈的操作和普通栈的操作没有太大区分,唯1多了1个方法就是getMin()方法,这个方法是用来获得当前栈内的最小值。其他方法就是Push(), Pop(), Top()...等
在O(n)时间内找到新的最小值
这里就利害了,先说普通的O(n)的方法~得到栈内最小值。是否是只要保护1个Min的变量就能够呢?不单单是!下面举例说明。
我们发现Min值是在第1次插入1
的时候为1
,第4次插入⑴
的时候变成⑴
,这个时候我们是否是觉得很简单,只用保护1个Min
就能够了?不是的!假定我们进行操作:Pop(),Pop()
操作。我们来看看堆栈里剩下了甚么。
stack 1 2 3
那末Min
呢?还是⑴
,但其实⑴
已被Pop()掉了。假设我们发现最小值被Pop()以后,我们如何更新Min
呢?只能从头遍历,那末就需要O(n)的时间。
O(1)的办法
这里说下如何O(1)时间内就找到,保护的变量没有变化,但是我们在堆栈内寄存的元素需要与Min值产生关联。
例子:
我们进行一样的5次Push操作,压栈顺序为1 2 3 ⑴ 4
。
- 第1次栈寄存0, Min为1.
- 第2次栈寄存2-Min=1, Min<2 所以继续为1.
- 第3次栈寄存3-Min=2, Min<3 所以继续为1.
- 第4次栈寄存⑴-Min=⑵, Min>⑴ 所以Min = ⑴.
- 第5次栈寄存4-Min=5, Min<5 所以继续为⑴.
大家看明白没?我们寄存的数为x-Min.
这是Push的操作,当我们进行Pop()的时候怎样做呢,进行两次Pop()?
第1次栈顶元素5, 5>0, 弹出,返回 5+Min=4.
第2次栈顶元素⑵, ⑵<0,弹出,返回Min. 并更新Min=Min-(⑵).
那Top呢?
假设栈顶元素为5, 5>0 返回5+Min.
假设栈顶元素为⑵, ⑵<0 返回Min.
大家发现没?实际上我们压栈的时候,压入的元素就是X-Min,那末只要压入的元素大于Min,那末寄存的都是正数,而当X小于Min的时候,压入的元素(X-Min)就是负数。
所以弹栈的时候:
遇到正数,直接弹出栈顶元素(X-Min)和Min的和(X-Min+Min)就能够了。
遇到负数,说明在压入这个元素的时候Min值有更新,那个时候的Min值被更新为新插入的X. 例如Min=1,插入⑴的时候,栈寄存⑴-Min=⑵,而Min更新为新的X值(⑴).则弹的时候就直接弹出Min就能够了。那末我们同时也把最小值弹出了,要更新Min,更新为当前Min-(X-下1个Min)此处比较绕,多用例子理解。
代码实现
我实现了4个版本,其中前两个版本是O(1)级别的,后两个是O(n)级别的。第2个版本可能有些瑕疵,假设你们看到代码哪里毛病请评论,多谢。
1号容器实现
自己写的结构体。
//
// main.cpp
// MinStack2
//
// Created by Alps on 14/12/3.
// Copyright (c) 2014年 chen. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
class MinStack {
public:
vector<int> stack;
int min;
void push(int x) {
if (stack.empty()) {
stack.push_back(0);
min = x;
}else{
stack.push_back(x-min);
if (x < min) {
min = x;
}
}
}
void pop() {
if (stack.empty()) {
return;
}else{
if (stack.back() < 0) {
min = min - stack.back();
}
stack.pop_back();
}
}
int top() {
if (stack.empty()) {
return NULL;
}
if (stack.back() > 0) {
return stack.back()+min;
}else{
return min;
}
}
int getMin() {
if (stack.empty()) {
return NULL;
}
return min;
}
};
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!
";
return 0;
}
2号STL的stack实现
在边沿测试的时候,我的编译器没出错,但是OJ上报WA了。
//
// main.cpp
// MinStack4_leetcode
//
// Created by Alps on 14/12/3.
// Copyright (c) 2014年 chen. All rights reserved.
//
#include <iostream>
#include <stack>
using namespace std;
class MinStack{
public:
stack<long> s;
long min;
void push(int x){
if (s.empty()) {
s.push(0);
min = x;
}else{
s.push(x-min);
if (x < min) {
min = x;
}
}
}
void pop(){
if (s.empty()) {
return;
}else{
if (s.top() < 0) {
min = min - s.top();
}
s.pop();
}
}
int top(){
if (s.empty()) {
return NULL;
}else{
if (s.top() > 0) {
return (int)(min+s.top());
}else{
return (int)min;
}
}
}
int getMin(){
if (s.empty()) {
return NULL;
}else{
return (int)min;
}
}
};
int main(int argc, const char * argv[]) {
int a = ⑵147483648;
MinStack M;
M.push(2147483646);
M.push(2147483646);
M.push(2147483647);
printf("%d
",M.top());
M.pop();
printf("%d
",M.getMin());
M.pop();
printf("%d
",M.getMin());
M.pop();
M.push(2147483647);
printf("%d
",M.top());
printf("%d
",M.getMin());
M.push(a);
printf("%d
",M.top());
printf("%d
",M.getMin());
M.pop();
printf("%d
",M.getMin());
return 0;
}
3号链表实现
自己写的链表结构体。
//
// main.cpp
// MinStack3_leetcode
//
// Created by Alps on 14/12/3.
// Copyright (c) 2014年 chen. All rights reserved.
//
#include <iostream>
using namespace std;
class MinStack {
public:
struct StackNode{
int num;
StackNode *next;
};
typedef StackNode* stack;
stack s;
MinStack(){
s = (stack)malloc(sizeof(struct StackNode));
s->next = NULL;
}
int min;
void push(int x) {
if (s->next == NULL) {
stack node = (stack)malloc(sizeof(struct StackNode));
node->num = x;
node->next = s->next;
s->next = node;
min = x;
}else{
stack node = (stack)malloc(sizeof(struct StackNode));
node->num = x;
node->next = s->next;
s->next = node;
if (x < min) {
min = x;
}
}
}
void pop() {
if (s->next == NULL) {
return;
}else{
stack temp = s->next;
if (min == s->next->num && s->next->next != NULL) {
s->next = s->next->next;
free(temp);
min = s->next->num;
for (stack loop = s->next; loop != NULL; loop = loop->next) {
if (min > loop->num) {
min = loop->num;
}
}
}else{
s->next = s->next->next;
free(temp);
}
}
}
int top() {
if (s->next == NULL) {
return NULL;
}
return s->next->num;
}
int getMin() {
if (s->next == NULL) {
return NULL;
}
return min;
}
};
int main(int argc, const char * argv[]) {
MinStack MinS;
MinS.push(⑴);
MinS.push(0);
MinS.push(2);
MinS.push(⑵);
printf("%d
",MinS.top());
MinS.pop();
MinS.pop();
MinS.pop();
printf("%d
",MinS.getMin());
return 0;
}
4号容器实现
最古老的版本。
//
// main.cpp
// MinStack_leetcode
//
// Created by Alps on 14/12/2.
// Copyright (c) 2014年 chen. All rights reserved.
//
#include <iostream>
#include "vector"
using namespace std;
class MinStack {
public:
struct StackNode{
int num;
int min;
};
vector<StackNode> stack;
void push(int x) {
if (stack.empty()) {
StackNode S = {x,x};
stack.push_back(S);
}else{
if (x < stack.back().min) {
StackNode S = {x,x};
stack.push_back(S);
}else{
StackNode S = {x,stack.back().min};
stack.push_back(S);
}
}
}
void pop() {
if (stack.empty()) {
}else{
stack.pop_back();
}
}
int top() {
if (stack.empty()) {
return NULL;
}
return stack.back().num;
}
int getMin() {
if (stack.empty()) {
return NULL;
}
return stack.back().min;
}
};
int main(int argc, const char * argv[]) {
MinStack minstack;
minstack.push(⑴);
minstack.push(1);
printf("%d %d
",minstack.top(), minstack.getMin());
return 0;
}
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠