一道IT技术面试题 带有max函数的栈

题目大意:要求实现一个栈,除了普通的pop()函数和push()函数外,还有一个max()函数,功能是返回栈中最大值,要求时间复杂度和空间复杂度尽量低。

 

      首先,很容易想到时间复杂度为O(1)的算法,我们设一个数组max[],max[i]表示从栈底到位置i的区间上的最大值,则我们插入的是后,设当前插入的位置是po,则我们比较max[po-1]和插入元素x的大小,较大值更新max[po],然后插入x,pop()的时候,照常弹出即可,计算getmax()函数时,我们只要返回max[top]即可(top为栈顶位置)。这个算法的时间复杂度为O(1),空间复杂度为O(n)。

     一个显然易见的优化就是,我们没有必要维护所有位置到栈底的最大值,容易发现,只有插入的值比当前栈中所有元素都大时,才需要更新max,所以我们将max数组替换成一个链表,链表指向上一次更新max值的位置。在插入时比较插入元素与当前最大值比较,若小于什么也不做,若大于则则加一个节点为当前节点,pop()时,看弹出的元素的位置是否是当前节点所指向的位置,若是的话,则将当前节点更新为下一个指向的节点(若没有返回错误码),getmax()函数的话,返回当前节点所代表的位置上的值即可。这样的话在平均情况下,时间复杂度和上述算法一样,但是空间复杂度有比较大的改进,但是在极端情况下,比如元素是按升序插入的话,空间复杂度还是O(n)。

 

    下面介绍时间复杂度和空间复杂度都是O(1)的算法,我们除了原有的栈stack[]数组外,只需两个额外变量top,表示栈顶元素位置,max表示当前栈中的最大值。我们在插入元素x时,插入的不是x,而是max-x,这时候,如果max-x小于0,说明插入的元素大于当前栈中的最大值,这是需要更新max,在弹出时,若弹出的元素x大于0,表示这个元素小于栈中最大值,则我们返回max-x,(因为前面我们存的是max-x,这时max-(max-x)==x,能很容易求出栈中到底村的是什么值),否则说明当前要弹出的数就是栈中的最大值,则我们将max弹出后,还要更新max=max+x(x<0),这时max依然为当前栈(去掉x后)中的最大值(想一想为什么),getmax()函数就直接返回max即可。这样一来,我们就可以在O(1)的时间复杂度和O(1)的空间复杂度完成题目所要求的功能了,详细实现请看以下代码。

 

#include <stdio.h>
#define maxn 110
using namespace std;
int stack[maxn],top,max=0;//max初始化为0,不妨设入栈的元素均大于0
void push(int x)
{
    stack[top++]=max-x;
    if(x>max)
    max=x;
}
int pop()
{
    if(top==0)//栈空
    return -1;//错误码
    int x;
    if(stack[top-1]<0)//表示要出栈的数是当前栈中的最大值,这时候要更新max
    {
        x=max;
        max+=stack[--top];
    }
    else
    {
        x=max-stack[--top];
    }
    return x;
}
int getmax()
{
    if(top==0)//栈空
    return -1;//错误码
    return max;
}
int main()
{
    //freopen("dd.txt","r",stdin);
    while(1)
    {
        int a,b;
        scanf("%d",&a);
        if(a==1)//执行push(x)语句
        {
            scanf("%d",&b);
            push(b);
        }
        else if(a==2)//执行pop语句
        printf("%d\n",pop());
        else if(a==3)//执行getmax()语句
        printf("%d\n",getmax());
        else//退出
        break;
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值