设计包含min函数的栈
。
定义栈的数据结构 ,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及po p的时间复杂度 都是O(1)。
定义栈的数据结构 ,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及po p的时间复杂度 都是O(1)。
我综合了别人的博客 最后一种给的一种非常规解法
其他两种是看见这个题目后想到的,第二种是把第一种另外一个栈结合到原栈里,可能与原有的栈略有不同,但是也是先进后出的结构!
第一种 两个栈解决时间
所以对于这种时间复杂度有要求的一般都是再建立一个辅助空间来存储所需信息
我这里建立的栈是head<--node<--。。。<--
这种反向链表形式
//============================================================================
// Name : MinStack.cpp
// Author : YLF
// Version :
// Copyright : Your copyright notice
// Description : get min in stack, Ansi-style
// 要考虑的问题是:如何实现时间复杂度为1 ,那就是得牺牲空间复杂度了,所以我们这里需要有个指针指向
// 当前最小的节点,但是如果pop掉了该节点,那么最小指针应该指向谁呢?
// 重新遍历找最小???那pop的时间复杂度变成o(n)
// 所以这里还需要一个链表专门记录最小节点的
//============================================================================
#include <iostream>
using namespace std;
struct LinkNode{
int value;
LinkNode* pPre;
};
void push(int);
LinkNode* pop();
LinkNode* getMin();
void printStack();
void preInput();
LinkNode* head = NULL;
LinkNode* cur = NULL;
LinkNode* minHead = NULL;
LinkNode* minCur = NULL;
int main() {
int input = 0;
preInput();
cin>>input;
while(input!=-1){
switch(input){
case 1:
cout<<"input num:";
cin>>input;
push(input);
break;
case 2:
LinkNode* pp;
pp = pop();
if(pp == NULL)
cout<<"stack is null"<<endl;
else
cout<<"pop:"<<pp->value<<endl;
break;
case 3:
if(minCur!=NULL)
cout<<"min value="<<minCur->value<<endl;
else
cout<<"the stack is null"<<endl;
break;
}
printStack();
cout<<endl;
preInput();
cin>>input;
}
return 0;
}
void push(int value)
{
LinkNode* p = new LinkNode();
p->value = value;
p->pPre = NULL;
if(head == NULL){
head = p;
//给最小的单独建立一个链表
LinkNode* pMin = new LinkNode();
pMin->value = value;
pMin->pPre = NULL;
minHead = pMin;
minCur = pMin;
}
else{
p->pPre = cur;
if(value <= minCur->value){
LinkNode* pMin = new LinkNode();
pMin->value = value;
pMin->pPre = minCur;
minCur = pMin;
}
}
cur = p;
}
LinkNode* pop()
{
if(head == NULL)
return NULL;
LinkNode* temp = cur;
if(cur!=head){
cur = cur->pPre;
}else{
head = NULL;
cur = NULL;
minHead = NULL;
minCur = NULL;
return temp;
}
if(temp->value == minCur->value){
LinkNode* minTemp = minCur;
minCur = minCur->pPre;
delete minTemp;
}
return temp;
}
LinkNode* getMin(){
return minCur;
}
void printStack()
{
LinkNode* temp = cur;
cout<<"----out-----"<<endl;
cout<<"stack:"<<endl;
while(temp!=NULL){
cout<<temp->value<<" ";
temp = temp->pPre;
}
temp = minCur;
cout<<endl<<"min stack:"<<endl;
while(temp!=NULL){
cout<<temp->value<<" ";
temp = temp->pPre;
}
cout<<endl<<"-----------"<<endl;
}
void preInput(){
cout<<"---------------menu--------------------"<<endl;
cout<<"input 1:push 2:pop 3:getMin -1 exit"<<endl;
cout<<"---------------------------------------"<<endl;
}
第二种:优化第一种,把另一个栈信息写入第一个栈
就是建立这样一个结构体
struct LinkNode{
int value;
LinkNode* pPre;
LinkNode* pMinPre;//这个指针用来指向比他更小的前一个节点
};
这个结构体每个节点如果是相对以前来说最小的,那么他存放一个指针,记录前面被取代的那个元素位置
这样就可以里利用链表的性质找到之前更小的了 例如1是最小的,如果pop()到1 的话,那么最小指针指向pMinPre也就是3了
//============================================================================
// Name : MinStack_2.cpp
// Author : YLF
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
using namespace std;
void push(int);
int pop();
int getMin();
void printStack();
void preInput();
//return -1 means exit
struct LinkNode{
int value;
LinkNode* pPre;
LinkNode* pMinPre;//这个指针用来指向比他更小的前一个节点
};
LinkNode* head;
LinkNode* cur;
LinkNode* pMin;//指向当前最小的
int main() {
int input = 0;
preInput();
cin>>input;
while(input!=-1){
int re = 0;
switch(input){
case 1:
cout<<"input num:";
cin>>input;
push(input);
break;
case 2:
re = pop();
if(-1 == re)
cout<<"stack is null"<<endl;
else
cout<<"pop:"<<re<<endl;
break;
case 3:
re = getMin();
if(-1 != re)
cout<<"min value="<<re<<endl;
else
cout<<"the stack is null"<<endl;
break;
}
printStack();
cout<<endl;
preInput();
cin>>input;
}
return 0;
}
void push(int value)
{
//新建节点
LinkNode* p = new LinkNode();
p->value = value;
p->pPre = NULL;
p->pMinPre = NULL;
if(head == NULL){
head = p;
pMin = p;
}else{
p->pPre = cur;
if(value <= pMin->value){
p->pMinPre = pMin;
pMin = p;
}
}
cur = p;
}
int pop()
{
LinkNode* p = cur;
if(head == NULL)
return -1;
int re = 0;
if(head == cur){
re = cur->value;
head = NULL;
cur = NULL;
pMin = NULL;
}else{
if(cur == pMin)
pMin = pMin->pMinPre;
cur = cur->pPre;
}
delete p;
return re;
}
int getMin(){
if(pMin!=NULL){
return pMin->value;
}
return -1;
}
void printStack()
{
LinkNode* temp = cur;
cout<<"----out-----"<<endl;
cout<<"stack:"<<endl;
while(temp!=NULL){
cout<<temp->value<<" ";
temp = temp->pPre;
}
temp = pMin;
cout<<endl<<"min stack:"<<endl;
while(temp!=NULL){
cout<<temp->value<<" ";
temp = temp->pMinPre;
}
cout<<endl<<"-----------"<<endl;
}
void preInput(){
cout<<"---------------menu--------------------"<<endl;
cout<<"input 1:push 2:pop 3:getMin -1 exit"<<endl;
cout<<"---------------------------------------"<<endl;
}
第三种:存储信息充分利用
大家可以参见上面这篇博客
就是存放的value不再是原始数据,而是转换过的数据,
比如
我们先存放第一个元素,5 存放后面的元素 如果
(1)value <= minVlaue 则存放value-minValue 例如4 存放的是4-5 (肯定<=0这是个重要的分水岭,用来恢复前一个最小值) 同时设置最小值
(2)value > minValue 则存放value-minValue 例如7 则7-5 肯定大于0 喽 所以pop时候注意如果<=0 那么要更新最小值
那么pop时候也要进行响应转换 见图描述 时间关系 代码以后再写了,大家理解下 还是挺容易的 想法不错!赞!