【剑指Offer】栈

这个系列是记录我刷《剑指Offer》这套题的过程,主要还是精刷,我的目的是能尽可能的用最优的方法解决和尽可能地把算法思路说明白。

用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTaildeleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

示例 1:

输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]

示例 2:

输入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]

提示:

  • 1 <= values <= 10000
  • 最多会对 appendTail、deleteHead 进行 10000 次调用

解法一:

class CQueue {
public:
    stack<int> a, b;
    CQueue() {
    }
    
    void appendTail(int value) {
        while(a.empty() != true){
            b.push(a.top());
            a.pop();
        }
        a.push(value);
        while(b.empty() != true){
            a.push(b.top());
            b.pop();
        }
    }
    
    int deleteHead() {
        if(a.empty())return -1;
        int ans = a.top();
        a.pop();
        return ans;
    }
};

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */

解法思路:

因为有两个栈,所以可以让一个栈在特定位置插入元素且不改变原栈内其它元素的次序,方法是将x个元素先从一个栈apoppush进另外一个栈b,将新元素push进栈a后再将栈b的所有元素poppush进栈a,这就完成了栈a内元素的按顺序插入。

因此队列(FIFO)的push实现可以是每次将新元素存入栈a的头部,pop则是栈a的直接pop。每次push时,先将栈a的所有元素存进栈b,向栈apush进新元素后,再把栈b中的元素push进栈a,这就完成了队列的插入。

解法一结果

解法二:

class CQueue {
public:
    stack<int> a, b;
    CQueue() {
    }
    
    void appendTail(int value) {
        a.push(value);
    }
    
    int deleteHead() {
        if(b.empty()){
            if(a.empty())return -1;
            while(a.empty() == false){
                b.push(a.top());
                a.pop();
            }
        }
        int ans = b.top();
        b.pop();
        return ans;
    }
};

解法思路

解法一非常容易想到,但也存在很多不足,每次CQueuepush操作都有两个栈的清空和填充,这是极浪费时间和没有必要的,我们再细想队列的特性,只有两个重要的结点,就是头和尾,我们可以用一个栈维护一个结点,也可以说是两个栈组成一个队列,就如下面的图(画得有亿点丑)
解法二

大概就是这样,s2是队列的入口,s1是出口,每次弹出时先检查s1是否为空,不为空直接弹出,空的话将s2的元素弹入s1,这样就避免了像解法一一样做很多无用的维护。

解法二结果

包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 minpushpop 的时间复杂度都是 O(1)

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

提示:

  • 各函数的调用总次数不超过 20000
class MinStack {
public:
    /** initialize your data structure here. */
    int n;
    vector<int> minn;
    stack<int> s;
    MinStack() {
        n = 0;
        minn.resize(20005);
    }
    
    void push(int x) {
        minn[n] = s.empty() ? x : ::min(x, minn[n - 1]);
        s.push(x);
        n ++;
    }
    
    void pop() {
        s.pop();
        n --;
    }
    
    int top() {
        return s.top();
    }
    
    int min() {
        return minn[n - 1];
    }
};

解法思路

这一题比较容易,就是记录每个结点所要的最小值,可以用栈存储,也可以直接用数组加指针,任何在栈弹出元素时指针前移即可。

最后

第一天的题还是比较简单的,都是考察栈的应用,都是简单题,希望我的博客能对你有所帮助。

新人博主发博,恳请各位不吝赐教,不胜感激,晚安。

题目链接:
用两个栈实现队列
包含min函数的栈

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值