【算法面试】队列算法笔试面试全解(金三银四面试专栏启动)

news2024/9/22 11:23:45

📫作者简介:小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。

        

📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。

        

🏆 CSDN博客专家 | CSDN后端领域优质创作者 | CSDN内容合伙人 | 2022博客之星

🏆 InfoQ(极客)签约作者、阿里云专家 | 签约博主、51CTO专家 | TOP红人、华为云享专家

        

🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~ 


🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

专栏系列(点击解锁)

学习路线(点击解锁)

知识定位

🔥Redis从入门到精通与实战🔥

Redis从入门到精通与实战

围绕原理源码讲解Redis面试知识点与实战

🔥MySQL从入门到精通🔥

MySQL从入门到精通

全面讲解MySQL知识与企业级MySQL实战

🔥计算机底层原理🔥

深入理解计算机系统CSAPP

以深入理解计算机系统为基石,构件计算机体系和计算机思维

Linux内核源码解析

围绕Linux内核讲解计算机底层原理与并发

🔥数据结构与企业题库精讲🔥

数据结构与企业题库精讲

结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

🔥互联网架构分析与实战🔥

企业系统架构分析实践与落地

行业最前沿视角,专注于技术架构升级路线、架构实践

互联网企业防资损实践

互联网金融公司的防资损方法论、代码与实践

🔥Java全栈白宝书🔥

精通Java8与函数式编程

本专栏以实战为基础,逐步深入Java8以及未来的编程模式

深入理解JVM

详细介绍内存区域、字节码、方法底层,类加载和GC等知识

深入理解高并发编程

深入Liunx内核、汇编、C++全方位理解并发编程

Spring源码分析

Spring核心七IOC/AOP等源码分析

MyBatis源码分析

MyBatis核心源码分析

Java核心技术

只讲Java核心技术

本文目录

本文目录

本文导读

一、采用数组和链表实现队列

二、两个栈实现队列

三、设计循环双端队列

四、滑动窗口最大值 

总结


本文导读

本文中的例题,采用数组与链表实现队列、用两个栈实现队列、设计循环双端队列、滑动窗口最大值,这几道题完全满足面试中队列的要求。

一、采用数组和链表实现队列

采用数组实现队列:

操作 LinkedList,put元素插入到尾部,pop元素的时候删除头结点 

class MyQueue<E> { // 数组实现队列
    private LinkedList<E> list = new LinkedList<E>();
    private int size = 0;

    public void put(E e) {
        list.addLast(e); // 插入尾部
        size++;
    }

    public E pop() {
        size--;
        return list.removeFirst(); // 删除头结点
    }

    public boolean empty() {
        return size == 0;
    }

    public int size() {
        return size;
    }
}

采用链表实现队列:

实现一个 node 单链表,put元素的时候插入一个新节点,操作 tail 指针指向新插入的节点,pop元素的时候,直接从头结点取出。

class Node<E> {
    Node<E> next = null;
    E data;

    public Node(E data) { this.data = data; }
}

public class MyQueue<E> {
    private Node<E> head = null;
    private Node<E> tail = null;

    public boolean isEmpty() {
        return head == tail;
    }

    public void put(E data) {
        Node<E> newNode = new Node<E>(data);
        if (head == null && tail == null) // 队列为空
            head = tail = newNode;
        else {
            tail.next = newNode; // 插入一个新节点
            tail = newNode; // tail变成新插入的节点

        }
    }

    public E pop() {
        if (this.isEmpty())
            return null;
        E data = head.data; // 从头结点取出
        head = head.next;
        return data;
    }

    public int size() {
        Node<E> tmp = head;
        int n = 0;
        while (tmp != null) {
            n++;
            tmp = tmp.next;
        }
        return n;
    }
}

二、两个栈实现队列

用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 

假设栈A和栈B用于模拟队列Q,其中A插入栈,B弹出栈,以实现队列Q。假设A和B都是空的,栈A提供了入队的功能,栈B提供了出队的功能

1、如果栈B不为空,则堆栈B的数据将直接弹出

2、如果栈B为空,则依次弹出栈A的数据,将其放入栈B,然后弹出栈B的数据

    Stack<Integer> s1 = new Stack<Integer>();
    Stack<Integer> s2 = new Stack<Integer>();
 
    public void push(int node) {
        s1.push(node);
    }
 
    public int pop() {
        if (s2.isEmpty()) {
            if (s1.isEmpty())
                return -1;
            while (!s1.isEmpty())
                s2.push(s1.pop()); // 则依次弹出栈A的数据,将其放入栈B
        }
        return s2.pop(); // 弹出栈B
    }

三、设计循环双端队列

题目描述:设计实现双端队列,实现 MyCircularDeque 类:

MyCircularDeque(int k) :构造函数,双端队列最大为 k 

boolean insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true ,否则返回 false 

boolean insertLast() :将一个元素添加到双端队列尾部。如果操作成功返回 true ,否则返回 false 

boolean deleteFront() :从双端队列头部删除一个元素。 如果操作成功返回 true ,否则返回 false 

boolean deleteLast() :从双端队列尾部删除一个元素。如果操作成功返回 true ,否则返回 false 

int getFront() ):从双端队列头部获得一个元素。如果双端队列为空,返回 -1 

int getRear() :获得双端队列的最后一个元素。 如果双端队列为空,返回 -1 

boolean isEmpty() :若双端队列为空,则返回 true ,否则返回 false 

boolean isFull() :若双端队列满了,则返回 true ,否则返回 false

解题思路:

构造一个与限定空间 k 等大的数组(capacity = k + 1),使用两下标(front、rear)并配合坐标转换来做,对于下标自增操作而言,只需要进行「加一取模」即可,而对于下标自减操作,由于考虑负值问题,需要进行「增加限定空间偏移后,进行减一再取模」。

对于一个固定大小的数组,只要知道队尾 rear 与队首 front,即可计算出队列当前的长度:( rear − front + capacity) % capacity。

 

class MyCircularDeque {
    private int[] elements; // 保存循环队列的元素
    private int front; // front 队列首元素对应的数组的索引
    private int rear;  // rear 队列尾元素对应的索引的下一个索引
    private int capacity; // 循环队列的容量

    /**
     * 初始化队列
     * front,rear 全部初始化为 0
     */
    public MyCircularDeque(int k) {
        capacity = k + 1;
        elements = new int[k + 1];
        rear = front = 0;
    }

    /**
     * 在队首插入一个元素
     * 将队首 front 移动一个位置,更新队首索引为 front 更新为 (front - 1 + capacity) % capacity
     */
    public boolean insertFront(int value) {
        if (isFull()) {
            return false;
        }
        front = (front - 1 + capacity) % capacity;
        elements[front] = value;
        return true;
    }

    /**
     * 在队尾部插入一个元素
     * 并同时将队尾的索引 rear 更新为 (rear + 1) % capacity
     */
    public boolean insertLast(int value) {
        if (isFull()) {
            return false;
        }
        elements[rear] = value;
        rear = (rear + 1) % capacity;
        return true;
    }

    /**
     * 从队首删除一个元素
     * 将队首的索引 front 更新为 (front + 1) % capacity
     */
    public boolean deleteFront() {
        if (isEmpty()) {
            return false;
        }
        front = (front + 1) % capacity;
        return true;
    }

    /**
     * 从队尾删除一个元素
     * 将队尾的索引 rear 更新为 (rear - 1 + capacity) % capacity
     */
    public boolean deleteLast() {
        if (isEmpty()) {
            return false;
        }
        rear = (rear - 1 + capacity) % capacity;
        return true;
    }

    /**
     * 返回队首的元素
     */
    public int getFront() {
        if (isEmpty()) {
            return -1;
        }
        return elements[front];
    }

    /**
     * 返回队尾的元素
     */
    public int getRear() {
        if (isEmpty()) {
            return -1;
        }
        return elements[(rear - 1 + capacity) % capacity];
    }

    /**
     * 检测队列是否为空
     */
    public boolean isEmpty() {
        return rear == front;
    }

    /**
     * 检测队列是否已满,判断 front 是否等于 (rear + 1) % capacity == front;
     */
    public boolean isFull() {
        return (rear + 1) % capacity == front;
    }
}

四、滑动窗口最大值 

题目描述:给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。

你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值

解题思路:

1、遍历给定数组中的元素

2、如果队列不为空且当前考察元素大于等于队尾元素,则将队尾元素移除,直到队列为空或当前考察元素小于新的队尾元素;

3、当队首元素的下标小于滑动窗口左侧边界left时,表示队首元素已经不再滑动窗口内,因此将其从队首移除

4、当窗口右边界right+1大于等于窗口大小k时(数组下标从0开始),意味着窗口形成,此时,队首元素就是该窗口内的最大值。

    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums.length < 2)
            return nums;

        // 双向队列就是滑动窗口
        LinkedList<Integer> queue = new LinkedList();
        int[] result = new int[nums.length - k + 1];

        for (int i = 0; i < nums.length; i++) {
            // 如果前面数小,则依次弹出
            while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) {
                queue.pollLast();
            }

            // 添加当前值对应的数组下标(比队列头小,才入队)
            queue.addLast(i);

            // 判断当前队列中队首的值是否有效
            if (queue.peek() <= i - k) { // peek()方法返回头对象(不删除)
                queue.poll(); // poll()方法返回头对象(会删除)
            }

            // 在双向队列头的才是有效的数,这个数需要返回到结果数组
            if (i + 1 >= k) {
                result[i + 1 - k] = nums[queue.peek()];
            }
        }
        return result;
    }

总结

本文中的例题,采用数组与链表实现队列、用两个栈实现队列、设计循环双端队列、滑动窗口最大值,这几道题完全满足面试中队列的要求,在实现双向队列时可以使用 LinkedList 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/177179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

02_gpio子系统

总结 驱动程序还想控制gpio 可以不用读写寄存器 直觉用gpio子系统开发的接口就能用了 轻松做输入输出 获取当前值 详细介绍 用设备树里的节点 gpio1 介绍 imx6ull.dtsi gpio1 记录了控制器相关的寄存器基地址 gpio1: gpio209c000 {compatible "fsl,imx6ul-gpio"…

三、利用迁移学习进行模型微调(Datawhale组队学习)

文章目录安装配置环境准备图像分类数据集迁移学习微调训练图像分类模型导入环境图像预处理载入图像分类数据集建立类别和索引号之间映射关系定义数据加载器查看一个batch的图像和标注可视化一个batch的图像和标注模型的构建与测试可视化常见的迁移学习训练方式训练配置模型训练…

过完2022,依然记得仰望星空

&#x1f57a;作者&#xff1a;一名普普通通的双非大二学生迷茫的启明星&#x1f383;专栏&#xff1a;《数据库》《C语言从0到1专栏》《数据结构》《C语言杂谈》目录 ​编辑 一.2022之初 二.2022年中 三.2022年末 四.展望2023 一.2022之初 想起一年前这个时候&#xff0c…

07_plantform平台总线

总结 /sys/bus/plantform 平台总线其实就是继承 06_自己创建xbus总线 有了更多的玩法 和自己创建的xbus总线一样 平台总线也有dev和drv 需要这两个进行匹配之后 进行porbe调用 plantform_device 结构体中直觉继承了 struc device lantform_driver 继承了driver 详细介绍 plan…

树(基础部分)

章节目录&#xff1a;一、二叉树1.1 为什么要使用树&#xff1f;1.2 树的常用术语1.3 二叉树概念1.4 二叉树应用二、顺序存储二叉树2.1 概述2.2 基本应用三、线索化二叉树3.1 问题引出3.2 概述3.3 基本应用四、结束语一、二叉树 1.1 为什么要使用树&#xff1f; 数组存储方式&…

MP-2平面烟雾气体传感器介绍

MP-2平面烟雾气体传感器简介MP-2烟雾检测气体传感器采用多层厚膜制造工艺&#xff0c;在微型Al2O3陶瓷基片的两面分别制作加热器和金属氧化物半导体气敏层&#xff0c;封装在金属壳体内。当环境空气中有被检测气体存在时传感器电导率发生变化&#xff0c;该气体的浓度越高&…

【数据库概论】3.1 SQL简述、数据定义和索引

第三章 关系数据库标准语言SQL 目录第三章 关系数据库标准语言SQL3.1 SQL概述3.1.1 产生与发展3.1.2 SQL的特点3.1.3 SQL的基本概念3.2 数据库实例3.3 数据定义3.3.1 模式的定义和删除3.2.2基本表的定义、删除和修改1.常见数据类型2.定义基本表3.修改基本表4.删除基本表5.模式和…

英语学习打卡day3

2023.1.22 1.mariner n.水手 2.formation n.队形;组成;形成 n.形状;形式样式;表格 the formation of landscapes Keep the formation 保持队形 The chairs were arranged in the form of circle. fill in the form 填写表格 formal adj.正式的inform 通知deform 变形uniform 统…

06_平台总线匹配规则,自己搭建总线xbus

总结 bus_register() 自己创建平台总线 /sys/bux/xxx device_register() 对平台总线加入dev /sys/bus/xxx/dev driver_register() 对平台总线加入drv /sys/bus/xxx/drv 两个相匹配的时候 直接调用drv->probe 函数 进行基本的class_create() device_create()等 创建设备文件…

TryHackMe-红队-07_武器化

Weaponization 了解并探索常见的红队武器化技术。您将学习如何使用业内常见的方法来构建自定义有效负载&#xff0c;以获得初始访问权限。 什么是武器化 武器化是网络杀伤链模式的第二阶段。在此阶段&#xff0c;攻击者使用可交付的有效负载&#xff08;如word文档&#xff…

七、python-PySpark篇(黑马程序猿-python学习记录)

1. pyspark定义 2. 下载 点击右下角版本 点击解释器设置 点击号 搜索pyspark 选择pyspark 勾选选项 在输入框中输入 -i https://pypi.tuna.tsinghua.edu.cn/simple 点击安装软件包 提示正在安装 等一两分钟就能安装完毕 3. 获取PySpark版本号 # 导包 from pyspark import Spar…

树,二叉树的认识

1.树概念及结构 1.1树的概念 注意&#xff1a;树形结构中&#xff0c;子树之间不能有交集&#xff0c;否则就不是树形结构 1.2 树的相关概念 1.3 树的表示 树结构相对线性表就比较复杂了&#xff0c;要存储表示起来就比较麻烦了&#xff0c;既然保存值域&#xff0c;也要保存…

(18)go-micro微服务ELK介绍

文章目录一 什么是ELK二 Beats的六种工具三 ELK系统的特点四 ELKbeats系统架构五 ELK优点六 最后一 什么是ELK ELK是三个[开源软件]的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件&#xff0c;新增了一个Beats。 Elasticsearch …

几种觉排序优劣

冒泡排序 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 对每一对相邻元素做同样的工作&#xff0c;从开始第一对到结尾的最后一对。在这一点&#xff0c;最后的元素应该会是最大的数。 针对所有的元素重复以上的步骤&#xff0c;除了最后一个。 持…

23. 异常处理机制

1. 异常 即便 python 程序的语法是正确的&#xff0c;在运行它的时候&#xff0c;也有可能发生错误。运行期检测到的错误被称为异常。 # int不能与str相加, 触发异常 print(22) # 0 不能作为除数, 触发异常 print(1/0) # sum未定义, 触发异常 print(num)异常以不同的类型出现…

【JavaSE专栏4】关键字、标识符和命名规范

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

k8s部署elk+filebeat。springCloud集成elk+filebeat+kafka+zipkin实现多个服务日志链路追踪聚合到es

一、目的 如今2023了&#xff0c;大多数javaweb架构都是springboot微服务&#xff0c;一个前端功能请求后台可能是多个不同的服务共同协做完成的。例如用户下单功能&#xff0c;js转发到后台网关gateway服务&#xff0c;然后到鉴权spring-sercurity服务&#xff0c;然后到业务…

mysql数据库管理-GTID详解

一、GTID概述 1 sql线程执行的事件也可以通过log_slave_updates系统变量来决定是否写入自己的二进制文件中&#xff0c;这是可以用于级联复制的场景。 GTID是MYSQL5.6新增的特性&#xff0c;GTID&#xff08;Global Transaction Identifier&#xff09;全称为全局事务标示符…

17种编程语言实现排序算法-计数排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

力扣sql简单篇练习(五)

力扣sql简单篇练习(五) 1 游戏玩法分析 I 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 第一次登录平台的日期就代表是时间靠前的日期 # 窗口函数是Mysql8版本后才能使用 SELECT e.player_id,e.event_date first_login FROM (SELECT player_id,e…