2021-04-30 15:10:14
三数之和:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 。找出所有满足条件且不重复的三元组。若完成较快,会加试题目,如 N皇后问题:在 N×N 的棋盘上放置 N 个皇后,使得它们互不攻击(即任意两个皇后不能处于同一行、同一列或同一对角线上)。可通过确定好每一行的值,利用回溯处理,结合判断条件(检查列和对角线是否冲突)来解决问题。
单例类实现:确保一个类只有一个实例,并提供一个全局访问点。常见实现方式有饿汉式(类加载时就初始化实例)、懒汉式(第一次使用时才初始化实例,需考虑线程安全问题,可通过同步方法或双重检查锁定等方式实现)。
项目概述:介绍项目背景、目标、整体架构和自己在项目中承担的角色与主要任务。
spdlog 和 glog 替换:spdlog 是一个高性能的 C++ 日志库,glog 是 Google 的开源日志库。替换时需考虑两者功能差异、接口兼容性、性能影响等方面。例如,分析原项目中 glog 的使用场景和功能需求,将 spdlog 的接口进行适配或调整项目代码中对日志库的调用方式,确保替换后日志功能正常且性能满足要求。
数据压缩处理过程:数据压缩旨在减少数据存储空间或传输带宽。常见过程包括选择压缩算法(如无损压缩的 Huffman 编码、LZ77 等,有损压缩的 JPEG 用于图像、MP3 用于音频等),对原始数据进行算法处理生成压缩数据,在需要使用时进行解压缩还原数据。需根据数据类型和应用场景选择合适的压缩算法。
池化操作过程:以对象池为例,预先创建一定数量的对象并放入池中。当需要使用对象时,从池中获取一个可用对象;使用完毕后,将对象归还到池中,而不是直接销毁,以便后续重复使用。这样可以减少频繁创建和销毁对象的开销,提高性能,如数据库连接池、线程池等。
TCP 的三次握手,四次挥手
三次握手:客户端发送 SYN 包(SYN=x)到服务器,进入 SYN_SEND 状态;服务器收到 SYN 包后,回复 SYN + ACK 包(SYN=y,ACK=x + 1),进入 SYN_RECV 状态;客户端收到 SYN + ACK 包后,回复 ACK 包(ACK=y + 1),双方进入 ESTABLISHED 状态,连接建立。
四次挥手:客户端发送 FIN 包(FIN=m)到服务器,进入 FIN_WAIT_1 状态;服务器收到 FIN 包后,回复 ACK 包(ACK=m + 1),进入 CLOSE_WAIT 状态;客户端收到 ACK 包后,进入 FIN_WAIT_2 状态;服务器处理完数据后,发送 FIN 包(FIN=n)到客户端,进入 LAST_ACK 状态;客户端收到 FIN 包后,回复 ACK 包(ACK=n + 1),进入 TIME_WAIT 状态,经过 2MSL 时间后关闭连接,服务器收到 ACK 包后立即关闭连接。
Java 相关
Java 的 HashMap 实现原理:基于哈希表实现,通过哈希函数将键映射到数组索引,将键值对存储在数组中。当发生哈希冲突时,采用链表法(Java 8 之前)或链表转红黑树(Java 8 及之后,当链表长度超过阈值 8 时)来解决。
红黑树的结构特点:是一种自平衡的二叉查找树,每个节点有颜色(红色或黑色),根节点是黑色,每个叶子节点(NIL 节点)是黑色,红色节点的两个子节点都是黑色,从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。这些特点保证了红黑树的平衡性,使得查找、插入和删除操作的时间复杂度为 O(log n)。
Java 编译一般经过几个步骤:包括词法分析(将源代码分解为单词符号)、语法分析(根据语法规则将单词符号组成语法短语)、语义分析(进行类型检查等语义检查)、中间代码生成(生成与机器无关的中间表示)、代码优化(对中间代码进行优化)、目标代码生成(将中间代码转换为目标机器代码)。
C++ 相关
指针和引用的区别:指针是一个变量,存储的是内存地址,可以为空,可以重新指向其他地址;引用是变量的别名,必须在定义时初始化,且初始化后不能改变引用其他变量,不能为空。
static 和 const 的区别:static 用于修饰变量时,表示静态存储期,整个程序运行期间都存在,可分为静态局部变量(只在定义它的函数内有效,但程序运行期间一直存在)和静态全局变量(作用域限于定义它的文件);用于修饰成员变量时,表示该变量属于类,所有对象共享;用于修饰成员函数时,表示该函数属于类,可直接通过类名调用。const 用于修饰变量时,表示该变量的值不可被修改;用于修饰指针时,有常量指针(指针指向的内容不可变)和指针常量(指针本身不可变)之分;用于修饰成员函数时,表示该函数不会修改对象的成员变量。
malloc 和 new 的差别:malloc 是 C 语言的库函数,用于在堆上分配指定字节数的内存,返回 void* 类型指针,需要手动计算所需字节数,且不会调用构造函数;new 是 C++ 的运算符,不仅分配内存,还会调用对象的构造函数,能根据对象类型自动计算所需内存大小。
项目评价:阐述项目优点(如功能完整性、性能优化、创新性等)和可能存在的不足(如代码可维护性、扩展性方面的问题等)及改进措施。
cmake 的 make -j4 多线程编译原理:make -j4 表示使用 4 个线程同时进行编译。cmake 生成 Makefile 文件后,make 命令根据 Makefile 中的依赖关系和规则来执行编译任务。-j 参数指定了并行编译的线程数,通过将可以并行执行的编译任务分配给不同线程,充分利用多核 CPU 的性能,加快编译速度。
编译的产物:根据不同的编程语言和编译目标有所不同。对于 C/C++ 项目,编译产物通常包括目标文件(.o 或.obj 文件,是源代码编译后的中间结果)和可执行文件(在 Windows 上是.exe 文件,在 Linux 上是无扩展名的可执行文件),还可能生成动态链接库(.so 文件,Linux;.dll 文件,Windows)或静态链接库(.a 文件,Linux;.lib 文件,Windows)。
单元测试方法:使用单元测试框架(如 C++ 的 Google Test、Java 的 JUnit 等)编写测试用例,对项目中的函数、类等最小可测试单元进行测试。测试用例应覆盖各种正常和异常情况,验证代码的正确性和健壮性。可以通过自动化测试工具定期运行测试用例,及时发现代码中的问题。
C++ 特性
封装、继承、多态:封装是将数据和操作数据的方法捆绑在一起,隐藏对象的内部实现细节,只对外提供必要的接口,增强代码的安全性和可维护性;继承是允许一个类继承另一个类的属性和方法,实现代码复用,可分为单继承和多继承(C++ 支持多继承,Java 不支持);多态是指同一操作作用于不同的对象,可以有不同的解释和不同的执行结果,通过虚函数实现运行时多态(动态绑定),通过函数重载和运算符重载实现编译时多态(静态绑定)。
STL 的容器和特点:STL(标准模板库)提供了多种容器,如序列容器(vector 可动态增长数组、deque 双端队列、list 双向链表、forward_list 单向链表、array 固定大小数组),关联容器(set 唯一键集合、multiset 可重复键集合、map 唯一键值对集合、multimap 可重复键值对集合,基于红黑树实现,元素有序;unordered_set 唯一键无序集合、unordered_multiset 可重复键无序集合、unordered_map 唯一键值对无序集合、unordered_multimap 可重复键值对无序集合,基于哈希表实现,元素无序),容器适配器(stack 栈、queue 队列、priority_queue 优先队列)。不同容器有不同的特点和适用场景,如 vector 适合随机访问,list 适合频繁插入和删除操作。
操作系统相关
线程和进程的差别:进程是资源分配的基本单位,拥有独立的地址空间、内存、文件等资源;线程是 CPU 调度和分派的基本单位,是进程的一个执行单元,同一进程内的线程共享进程的资源。线程的创建、切换和通信开销比进程小,能更高效地利用系统资源,提高程序的并发性能。
进程通信的方式:包括管道(匿名管道用于有亲缘关系的进程间通信,命名管道可用于无亲缘关系的进程间通信)、消息队列、共享内存(效率最高,但需要同步机制来保证数据的一致性)、信号量(用于同步和互斥)、套接字(可用于不同主机间的进程通信)。
MySQL 相关
MySQL 事务的特点:原子性(事务是一个不可分割的工作单位,事务中的操作要么都做,要么都不做)、一致性(事务执行的结果必须使数据库从一个一致性状态变到另一个一致性状态)、隔离性(一个事务的执行不能被其他事务干扰)、持久性(一个事务一旦提交,它对数据库中数据的改变就应该是永久性的)。
死锁的特点、解决方法及锁的类型:死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,这些事务都将无法继续执行下去。解决方法有预防死锁(如按顺序申请资源、一次性申请所有资源等)、避免死锁(如银行家算法)、检测死锁(通过检测资源分配图等判断是否存在死锁)和解除死锁(如撤销一些事务,释放资源)。MySQL 中的锁包括共享锁(S 锁,多个事务可以同时读取同一数据,但不允许其他事务获取排他锁)、排他锁(X 锁,一个事务获取了排他锁后,其他事务不能获取该数据的任何锁)、意向锁(表级锁,表示事务打算在表中的行上获取什么类型的锁,分为意向共享锁和意向排他锁)等。
实习与项目差异及自身优势:实习项目通常更注重实际业务场景的应用和团队协作,能接触到公司级的项目架构和开发流程;平时做的项目可能更侧重于技术的学习和探索,自主性更强。相比于其他实习生,自身优势可以从技术能力(如熟练掌握多种编程语言、对特定技术有深入研究)、学习能力(能快速掌握新知识和技能)、沟通能力(能与团队成员有效沟通和协作)、问题解决能力(能独立分析和解决复杂问题)等方面阐述。
对安卓岗位的看法:安卓是全球最大的移动操作系统之一,安卓开发岗位具有广阔的发展前景。可以从安卓系统的普及程度、应用领域的广泛性(如手机、平板、智能穿戴设备、智能汽车等)、技术栈的丰富性(涉及 Java、Kotlin、Android SDK、UI 设计、性能优化等多个方面)以及个人对移动开发的兴趣和职业规划等方面表达对安卓岗位的看法。
快排:快速排序是一种分治的排序算法。选择一个基准元素,将数组分为两部分,使得左边部分的所有元素都小于等于基准,右边部分的所有元素都大于等于基准,然后递归地对左右两部分进行快速排序。
智力题:将 8 个球分成 3 组,分别为 3 个、3 个、2 个。第一次称量,将两组 3 个球放在天平两端:若天平平衡,则最重的球在剩下的 2 个球中,再进行一次称量即可确定;若天平不平衡,则最重的球在天平下沉的那一组的 3 个球中,从这 3 个球中任取 2 个进行第二次称量,若平衡,则剩下的那个球是最重的,若不平衡,则下沉的那个球是最重的。
MySQL 的四种隔离级别
读未提交(Read Uncommitted):一个事务可以读取另一个未提交事务修改过的数据,可能出现脏读(读取到其他事务未提交的脏数据)、不可重复读(同一事务内多次读取同一数据,结果不一致)和幻读(同一事务内多次查询,结果集的行数不一致)问题。
读已提交(Read Committed):一个事务只能读取另一个已提交事务修改过的数据,解决了脏读问题,但仍可能出现不可重复读和幻读问题。
可重复读(Repeatable Read,MySQL 默认隔离级别):同一事务内多次读取同一数据,结果一致,解决了脏读和不可重复读问题,但在某些情况下仍可能出现幻读问题(MySQL 通过多版本并发控制 MVCC 和间隙锁在一定程度上解决了幻读问题)。
串行化(Serializable):所有事务串行执行,事务之间完全隔离,避免了脏读、不可重复读和幻读问题,但并发性能最低。
可重复读的实现原理:MySQL 通过 MVCC(多版本并发控制)来实现可重复读隔离级别。MVCC 为每个事务分配一个唯一的事务 ID(trx_id),在数据行中存储创建版本号(创建该行的事务 ID)和删除版本号(删除该行的事务 ID)。当事务读取数据时,只能读取创建版本号小于等于当前事务 ID 且删除版本号为空或大于当前事务 ID 的数据行,从而保证同一事务内多次读取的数据一致。
MySQL 索引相关
索引类型及 B + 树索引失效情况:MySQL 的索引包括 B + 树索引(最常用,适用于全值匹配、范围查询、前缀匹配等)、哈希索引(仅用于等值查询,Memory 引擎支持)、全文索引(用于全文搜索,MyISAM 和 InnoDB 引擎支持)、空间索引(用于地理空间数据类型,MyISAM 引擎支持)。B + 树索引失效情况包括:对索引列使用函数或表达式进行查询(如 WHERE YEAR(create_time) = 2023)、使用不等于(!= 或 <>)操作符、使用 IS NULL 或 IS NOT NULL 进行判断(除非该列定义了 NOT NULL 约束)、使用 LIKE 以通配符开头(如 %abc)、使用 OR 条件连接多个查询条件(除非所有列都有索引)、联合索引不满足最左前缀原则等。
聚簇索引和非聚簇索引的差别:聚簇索引的叶子节点存储的是完整的数据记录,一个表只能有一个聚簇索引,通常主键作为聚簇索引;非聚簇索引的叶子节点存储的是主键值,而不是完整的数据记录,一个表可以有多个非聚簇索引。查询时,如果使用聚簇索引查询,可以直接获取数据;如果使用非聚簇索引查询,需要先通过非聚簇索引找到主键值,再通过主键值到聚簇索引中查找数据,这个过程称为回表。
TCP 和 UDP 的差别
连接方面:TCP 是面向连接的协议,通信前需要建立连接(三次握手),通信结束后需要释放连接(四次挥手);UDP 是无连接的协议,不需要建立和释放连接,直接发送数据。
可靠性方面:TCP 提供可靠的传输服务,通过确认机制、重传机制、流量控制和拥塞控制等保证数据的可靠传输;UDP 不保证数据的可靠传输,不提供确认、重传等机制,数据可能丢失、重复或乱序。
传输效率方面:由于 TCP 需要建立连接、维护连接状态和进行可靠性控制等,传输效率相对较低;UDP 无需这些开销,传输效率较高。
应用场景方面:TCP 适用于对可靠性要求较高的应用,如文件传输、电子邮件、网页浏览等;UDP 适用于对实时性要求较高、允许一定数据丢失的应用,如视频流、音频流、实时游戏等。
HTTP3.0 使用 UDP 实现的情况:HTTP3.0 基于 QUIC 协议,QUIC 是一种基于 UDP 的传输层协议。HTTP3.0 使用 UDP 实现的主要原因是为了解决 HTTP2.0 中存在的队头阻塞问题(HTTP2.0 虽然多路复用,但一个 TCP 连接上的某个流丢失或阻塞会影响其他流的传输)。QUIC 通过多路复用、快速握手、前向纠错等技术,在 UDP 的基础上提供了类似 TCP 的可靠性保障,同时提高了传输效率和性能,特别是在网络环境较差的情况下表现更好。