225. Implement Stack using Queues 解答

Approach #1 (Two Queues, push - O(1)O(1), pop O(n)O(n) )

Intuition

Stack is LIFO (last in - first out) data structure, in which elements are added and removed from the same end, called top. In general stack is implemented using array or linked list, but in the current article we will review a different approach for implementing stack using queues. In contrast queue is FIFO (first in - first out) data structure, in which elements are added only from the one side - rear and removed from the other - front. In order to implement stack using queues, we need to maintain two queues q1 and q2. Also we will keep top stack element in a constant memory.

Algorithm

Push

The new element is always added to the rear of queue q1 and it is kept as top stack element

Push an element in stack

Figure 1. Push an element in stack

Java

private Queue<Integer> q1 = new LinkedList<>();
private Queue<Integer> q2 = new LinkedList<>();
private int top;

// Push element x onto stack.
public void push(int x) {
    q1.add(x);
    top = x;
}

Complexity Analysis

  • Time complexity : O(1)O(1). Queue is implemented as linked list and add operation has O(1)O(1) time complexity.

  • Space complexity : O(1)O(1)

Pop

We need to remove the element from the top of the stack. This is the last inserted element in q1. Because queue is FIFO (first in - first out) data structure, the last inserted element could be removed only after all elements, except it, have been removed. For this reason we need to maintain additional queue q2, which will serve as a temporary storage to enqueue the removed elements from q1. The last inserted element in q2 is kept as top. Then the algorithm removes the last element in q1. We swap q1 with q2 to avoid copying all elements from q2 to q1.

Pop an element from stack

Figure 2. Pop an element from stack

Java

// Removes the element on top of the stack.
public void pop() {
    while (q1.size() > 1) {
        top = q1.remove();
        q2.add(top);
    }
    q1.remove();
    Queue<Integer> temp = q1;
    q1 = q2;
    q2 = temp;
}

Complexity Analysis

  • Time complexity : O(n)O(n). The algorithm dequeues n elements from q1 and enqueues n - 1n1 elements to q2, where nn is the stack size. This gives 2n - 12n1operations.
  • Space complexity : O(1)O(1).

Approach #2 (Two Queues, push - O(n)O(n), pop O(1)O(1) )

Algorithm

Push

The algorithm inserts each new element to queue q2 and keep it as the top element. In case queue q1 is not empty (there are elements in the stack), we remove all elements from q1 and add them to q2. In this way the new inserted element (top element in the stack) will be always positioned at the front of q2. We swap q1 with q2 to avoid copying all elements from q2 to q1.

Push an element in stack

Figure 3. Push an element in stack

Java

public void push(int x) {
    q2.add(x);
    top = x;
    while (!q1.isEmpty()) {                
        q2.add(q1.remove());
    }
    Queue<Integer> temp = q1;
    q1 = q2;
    q2 = temp;
}

Complexity Analysis

  • Time complexity : O(n)O(n). The algorithm removes n elements from q1 and inserts n + 1n+1 elements to q2, where n is the stack size. This gives 2n + 12n+1operations. The operations add and remove in linked lists has O(1)O(1) complexity.

  • Space complexity : O(1)O(1).

Pop

The algorithm dequeues an element from queue q1 and keeps front element of q1 as top.

Pop an element from stack

Figure 4. Pop an element from stack

Java

// Removes the element on top of the stack.
public void pop() {
    q1.remove();
    if (!q1.isEmpty()) {
        top = q1.peek();
    }
}

Complexity Analysis

  • Time complexity : O(1)O(1).
  • Space complexity : O(1)O(1).

In both approaches empty and top operations have the same implementation.

Empty

Queue q1 always contains all stack elements, so the algorithm checks q1 size to return if the stack is empty.

// Return whether the stack is empty.
public boolean empty() {
    return q1.isEmpty();
}

Time complexity : O(1)O(1).

Space complexity : O(1)O(1).

Top

The top element is kept in constant memory and is modified each time when we push or pop an element.

// Get the top element.
public int top() {
    return top;
}

Time complexity : O(1)O(1). The top element has been calculated in advance and only returned in top operation.

Space complexity : O(1)O(1).


Approach #3 (One Queue, push - O(n)O(n), pop O(1)O(1) )

The mentioned above two approaches have one weakness, they use two queues. This could be optimized as we use only one queue, instead of two.

Algorithm

Push

When we push an element into a queue, it will be stored at back of the queue due to queue's properties. But we need to implement a stack, where last inserted element should be in the front of the queue, not at the back. To achieve this we can invert the order of queue elements when pushing a new element.

Push an element in stack

Figure 5. Push an element in stack

Java

private LinkedList<Integer> q1 = new LinkedList<>();

// Push element x onto stack.
public void push(int x) {
    q1.add(x);
    int sz = q1.size();
    while (sz > 1) {
        q1.add(q1.remove());
        sz--;
    }
}

Complexity Analysis

  • Time complexity : O(n)O(n). The algorithm removes n elements and inserts n + 1n+1 elements to q1 , where n is the stack size. This gives 2n + 12n+1 operations. The operations add and remove in linked lists has O(1)O(1) complexity.

  • Space complexity : O(1)O(1).

Pop

The last inserted element is always stored at the front of q1 and we can pop it for constant time.

Java

// Removes the element on top of the stack.
public void pop() {
    q1.remove();
}

Complexity Analysis

  • Time complexity : O(1)O(1).
  • Space complexity : O(1)O(1).

Empty

Queue q1 contains all stack elements, so the algorithm checks if q1 is empty.

// Return whether the stack is empty.
public boolean empty() {
    return q1.isEmpty();
}

Time complexity : O(1)O(1).

Space complexity : O(1)O(1).

Top

The top element is always positioned at the front of q1. Algorithm return it.

// Get the top element.
public int top() {
    return q1.peek();
}

Time complexity : O(1)O(1).

Space complexity : O(1)O(1).

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值