代码随想录算法训练营第十天 | LeetCode 232.用栈实现队列、LeetCode 225. 用队列实现栈

简介: 代码随想录算法训练营第十天 | LeetCode 232.用栈实现队列、LeetCode 225. 用队列实现栈

1. 栈与队列理论基础

1.1 栈-概念

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFOLast In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶

出栈:栈的删除操作叫做出栈。出数据在栈顶

1.2 栈-使用

Stack继承了VectorVectorArrayList类似,都是动态的顺序表,不同的是Vector是线程安

全的。

1.3 栈-模拟实现

public class MyStack {
    private int[] elem;
    private int usedSize;
    public MyStack() {
        this.elem = new int[5];//初始长度为5,随你定
    }
    //入栈
    public void push(int val) {
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length);//如果满了扩容
        }
        elem[usedSize] = val;
        usedSize++;
    }
    //栈是否满
    public boolean isFull() {
        return usedSize == elem.length;
    }
    //出栈
    public int pop() {
        //判断栈是否为空
        if (empty()) {//抛出栈空异常
            throw new StackEmptyException("栈为空");
        }
        //开始删除
        //这种删除方法原理就是把usedSize往前挪,原本最后位置的元素就放在那但没法调用了,下次添加元素就直接覆盖
        return elem[--usedSize];//如果是return elem[usedSize--]就没有返回最后的元素,是返回最后元素的下一个位置
    }
    //栈是否为空
    public boolean empty() {
        return usedSize == 0;
    }
    //获取栈顶元素,但不弹出
    public int peek() {
        //判断栈是否为空
        if (empty()) {//抛出栈空异常
            throw new StackEmptyException("栈为空");
        }
        //开始获取
        return elem[usedSize - 1];//不用删除,只需要获取
    }
    //递归打印
    public void recursivePrint(MyStack stack) {
        if (!stack.empty()) {
            int value = stack.pop(); // 弹出栈顶元素
            recursivePrint(stack); // 递归打印剩余栈中的元素
            System.out.print(value + " "); // 打印当前弹出的元素
            stack.push(value); // 将元素重新压回栈中,保持栈的原有状态
        }
    }
}

1.4 队列-概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)。

入队列:进行插入操作的一端称为队尾(Tail/Rear

出队列:进行删除操作的一端称为队头Head/Front)

1.5 队列-使用

Java中,Queue是个接口,底层是通过链表实现的。

注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

1.6 队列-模拟实现

public class MyQueue {
    static class ListNode{
        public int val;
        public ListNode next;//单链表实现队列
        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    public ListNode last;//方便实现单链表的尾插法
    public int usedSize;
    //入队操作(单链表的尾插法)
    public void offer(int val){
        ListNode node=new ListNode(val);
        if(head==null){
            head=node;
            last=node;
        }else{
            last.next=node;
            last=last.next;
        }
    }
    public int getUsedSize(){
        return usedSize;
    }
    //弹出元素(单链表的删除头节点)
    public int poll(){
        if(head==null){
            return -1;
        }
        int val=-1;
        if(head.next==null){
            val=head.val;
            head=null;
            last=null;
            return val;
        }
        val= head.val;
        head=head.next;
        usedSize--;
        return val;
    }
    //获取队头元素
    public int peek(){
        if(head==null){
            return -1;
        }
        return head.val;
    }
}

2. LeetCode 232. 用栈实现队列

2.1 思路

  1. 队列是先进先出的,栈是先进后出的,用一个栈模拟队列的先进先出的行为是不可能的,肯定是先进后出,因此借用另一个栈
  2. 此时两个栈一个叫输入栈一个叫输出栈,类似负负得正的思想,做两次先进后出就做到了先进先出的操作了
  3. 进队:这个操作很简单,全部进入输入栈
  4. 出队:这个操作比较难,当输出栈为空时,就需要把输入栈的元素全部按照栈出栈的方式然后进入输出栈,此时顺序就是一致的了,一直到输出栈为空才把输入栈的元素全部放入到输出栈中,注意是全部,如果不是全部,那顺序会乱的
  5. 查看队首元素:类似出队的方式,只是不要弹出,只是查看
  6. 判断队列是否为空:输入栈和输出栈均为空则模拟队列为空
  7. 注意,定义stack1和stack2时不要在构造方法里声明创建,这样是局部变量的,下面的方法访问不到,因此要声明为全局变量

2.2 代码

class MyQueue {
    Stack<Integer> stackIn;
    Stack<Integer> stackOut;
    /** Initialize your data structure here. */
    public MyQueue() {
        stackIn = new Stack<>(); // 负责进栈
        stackOut = new Stack<>(); // 负责出栈
    }
    /** Push element x to the back of queue. */
    public void push(int x) {
        stackIn.push(x);
    }
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {    
        dumpstackIn();
        return stackOut.pop();
    }
    /** Get the front element. */
    public int peek() {
        dumpstackIn();
        return stackOut.peek();
    }
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();
    }
    // 如果stackOut为空,那么将stackIn中的元素全部放到stackOut中
    private void dumpstackIn(){
        if (!stackOut.isEmpty()) return; 
        while (!stackIn.isEmpty()){
                stackOut.push(stackIn.pop());
        }
    }
}

3. LeetCode 225. 用队列实现栈

3.1 思路

  1. 可用一个队列实现模拟实现栈,也可用两个队列实现,下面将一个队列的
  2. 这里关键在于出栈操作:我们按照正常顺序入队1、2、3,正常顺序入栈1、2、3,按照栈应该弹出的是3先,但队列是先弹出1,因此我们让前两个元素依次进行出队、入队的操作,就是先出队然后立刻入队,这样原来的队首元素就跑到队尾了,直到进行到元素3才停止,这时出队就是3了
  3. 问题关键:怎么知道先把1、2先弹出,然后再弹出3,那么我们假设队列有size个元素,就把size-1个元素依次先弹出再入队,然后再把原本最后一个元素弹出即可

3.2 代码

class MyStack {
    Queue<Integer> queue;
    public MyStack() {
        queue = new LinkedList<>();
    }
    public void push(int x) {
        queue.add(x);
    }
    public int pop() {
        rePosition();
        return queue.poll();
    }
    public int top() {
        rePosition();
        int result = queue.poll();
        queue.add(result);
        return result;
    }
    public boolean empty() {
        return queue.isEmpty();
    }
    public void rePosition(){
        int size = queue.size();
        size--;
        while(size-->0)
            queue.add(queue.poll());
    }
}

3.3 用两个队列实现栈的代码

class MyStack {
    //q1作为主要的队列,其元素排列顺序和出栈顺序相同
    Queue<Integer> q1 = new ArrayDeque<>();
    //q2仅作为临时放置
    Queue<Integer> q2 = new ArrayDeque<>();
    public MyStack() {
    }
    //在加入元素时先将q1中的元素依次出栈压入q2,然后将新加入的元素压入q1,再将q2中的元素依次出栈压入q1
    public void push(int x) {
        while (q1.size() > 0) {
            q2.add(q1.poll());
        }
        q1.add(x);
        while (q2.size() > 0) {
            q1.add(q2.poll());
        }
    }
    public int pop() {
        return q1.poll();
    }
    public int top() {
        return q1.peek();
    }
    public boolean empty() {
        return q1.isEmpty();
    }
}
相关文章
|
8月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
749 0
|
8月前
|
机器学习/深度学习 算法 机器人
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
374 8
|
8月前
|
机器学习/深度学习 算法 自动驾驶
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
431 8
|
8月前
|
机器学习/深度学习 数据采集 负载均衡
结合多种启发式解码方法的混合多目标进化算法,用于解决带工人约束的混合流水车间调度问题(Matlab代码实现)
结合多种启发式解码方法的混合多目标进化算法,用于解决带工人约束的混合流水车间调度问题(Matlab代码实现)
402 0
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
449 6
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
238 6
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
541 2
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
453 4
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
493 1
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
570 7

热门文章

最新文章