【剑指Offer记录】9_用两个栈实现队列

文章讲述了作者尝试用两个队列模拟栈的过程,首先提出了一种将栈1元素转移至栈2的实现,导致时间复杂度为O(n)。随后介绍了书中的方法,通过控制栈2的使用,使得大部分pop操作的时间复杂度降低到O(1),强调了优化意识在解决问题中的重要性。
摘要由CSDN通过智能技术生成

Part1. 我的思路和代码

将栈1的所有元素依次出栈并压入栈2中,栈2元素的顺序就与栈1相反,即栈2从顶到底的元素就是“从先到后压入栈1”的元素,对栈2进行出栈操作时,效果就如同队列头部的pop操作。具体做法为:push操作时,仅将元素压入stack1;而pop操作时,先将stack1的元素依次出栈并压入stack2中,stack2的顶部就是队列头部的元素,让其出栈,然后再把stack2的元素依次出栈并压入stack1中,还原stack1元素本来的顺序。

按此方案编写的代码可以通过,但队列的pop操作中每次都需要把所有元素从stack1转移到stack2,于是时间复杂度为O(n),不是题目要求的O(1)

stack<int> stack1;
stack<int> stack2;

void push(int node) {
    stack1.push(node);
}

int pop() {
    int ans = 0;

    while(stack1.empty() == false){ //将栈1的元素转到栈2中
        int temp = stack1.top();
        stack1.pop();
        stack2.push(temp);
    }
    ans = stack2.top();
    stack2.pop();
    while(stack2.empty() == false){ //还原栈1的元素
        int temp = stack2.top();
        stack2.pop();
        stack1.push(temp);
    }

    return ans;
}

Part2. 其他做法

书中给出的做法

我和书中做法不同的地方是:书中将stack1的元素转移到stack2后,没有再将stack2的元素转回到stack1,而是根据stack2是否为空减少了操作次数。具体地,当进行队列的pop操作时,若stack2为空,则将stack1的元素依次出栈并压入stack2,和我的实现相同;而stack2不为空时,队列进行pop操作时,继续让stack2的栈顶元素出栈即可。队列进行push操作时,同样为仅将元素压入stack1。

这种方式下,队列的pop操作时间复杂度有时为O(n)有时为O(1),但平均考虑下主要为O(1)

stack<int> stack1;
stack<int> stack2;

void push(int node) {
    stack1.push(node);
}

int pop() {
    int ans = 0;

    if(stack2.empty()){ //若栈2为空,先将栈1的元素依次出栈并压入栈2
        while(stack1.empty() == false){
            int temp = stack1.top();
            stack1.pop();
            stack2.push(temp);
        }
    }
    ans = stack2.top(); //这些语句不是else分支,因为无论栈2是否为空都需要进行此操作
    stack2.pop();

    return ans;
}

Part3. 相关题目

用两个队列模拟一个栈。

我的想法

定义两个队列q1和q2。栈的push操作中,先将q1中的所有元素依次出队并入队到q2,接着将新元素入队q1,再将q2的所有元素依次出队并入队到q1,在这样的操作后,q1中的元素被倒转;栈的pop操作中,q1队首元素正常出队即可,因为栈的push操作时q1的元素已经被倒转

栈的push操作时间复杂度为O(n),想优化一下看能不能和“用两个栈实现队列”时从书中学到的做法一样,让多数情况下时间复杂度为O(1),但没有想出来,于是接下来看书上是怎么解释的。

其他做法

书上的做法是:栈的pop操作中,将非空队列除队尾外的元素都入队到另一个队列,剩下的队尾元素就是应该出栈的元素,相当于两个队列交替使用,时间复杂度也是O(n);栈的push操作中,将新元素入队到非空的那个队列。该做法中时间复杂度高的操作位于栈的pop操作,而我的方法是位于栈的push操作,且由于队列的交替使用,复杂度比我的更低(我需要将近操作两遍完整的队列,而书中的方法仅操作一遍)。

Part4. 心得体会

  • 在之前的“6_从尾到头打印链表”中,我记录到“对stack的用法陌生了些”,这次不得不使用了()。
  • 读过题目后,想到了大二用的紫白色数据结构书的一张图,那张图就展示了栈和队列的联系,然而已经不记得了。想了一阵子后,得到的是时间复杂度为O(n)的方法。
  • 没有看书中的方法时,我以为O(1)复杂度意味着不能有类似“将某个栈的元素全部转移到另一个栈”的操作,于是想了很久也没有思路,看过书中的方法后,得知这样的操作不是每次pop操作时都要进行,多数情况下时间复杂度还是O(1)的,比自己的方法要高效很多。
  • 思考相关题目的过程练习了我的优化意识
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值