知识点标签

数据结构面试题解析

数据结构相关面试题解析,按真实面经题目沉淀核心机制、易错点和面试官追问。

59 道题 5 个岗位 10 个公司

数据结构相关面试题

ArrayList 是怎么扩容的?

ArrayList 的扩容本质是底层 Object[] 容量不足时创建更大的数组并复制旧元素。常见 OpenJDK 实现中,空参构造会延迟分配默认容量,首次添加时通常扩到 10;后续容量不够时按约 1.5 倍增长。面试回答要同时讲清 add 触发路径、复制成本、均摊复杂度、极限容量和与数组、LinkedList 的差异。

分词算法有哪些?

分词算法解决的是把连续文本切成有意义的词或子词单位。中文没有天然空格,因此分词既要处理词典匹配,也要处理歧义、未登录词、新词、专名、领域词和下游任务适配。常见算法包括基于词典的正向/逆向/双向最大匹配、DAG 加动态规划、HMM/CRF 序列标注、统计语言模型、深度学习序列标注,以及 BPE、WordPiece、SentencePiece 等子词切分方法。

同题还出现在 2 个公司岗位

CAN降低的是计算复杂度还是存储复杂度?

这里的 CAN 按推荐和 CTR 建模语境理解为 Co-Action Network。它的核心不是把线上推理的所有计算量都变少,而是把显式二阶或高阶交叉带来的参数量、存储量和稀疏组合记忆压力降下来。它通过让一个特征参与生成或选择作用于另一个特征的交互权重,用参数共享和动态交互替代海量离散交叉参数,因此主要回答应落在存储复杂度、参数复杂度和长尾稀疏性上,同时承认会引入一定运行时计算。

推荐系统的召回、排序和重排链路如何理解?

这道题考察候选人是否能从工程链路而不是单点模型理解推荐系统:召回负责从海量候选中高覆盖地捞出可能感兴趣的内容,排序负责用特征和模型估计用户行为价值,重排负责在最终曝光前加入多样性、新鲜度、去重、业务规则和体验约束,同时还要兼顾在线延迟、离线评估和 A/B 实验闭环。

同题还出现在 1 个公司岗位

StringBuffer的底层数据结构?

StringBuffer 的底层核心是一个可变的连续缓冲区,而不是每次修改都创建新的 String。常见实现中,真正负责存储、长度、容量和扩容的是 AbstractStringBuilder;早期实现可理解为 char[],JDK 9+ 常见实现为了紧凑字符串改为 byte[] 加 coder 标记,但对外仍表现为可变字符序列。StringBuffer 的特点是在这套可变缓冲区能力之上,用 synchronized 保护关键操作,因此适合多个线程共享同一个实例时使用;单线程场景通常优先 StringBuilder。

对哪些分类算法有研究?

这道题考察的不是背诵分类算法列表,而是候选人能否把分类问题的建模假设、算法家族、适用场景、优缺点、评估方法和工程选择讲清楚。高质量回答应围绕线性模型、树模型与集成方法、核方法、概率模型、神经分类器、文本/NLP分类器以及评估和选型逻辑展开,并能结合特征稀疏性、样本规模、类别不均衡、可解释性、线上延迟等因素说明取舍。

数组和链表、队列和栈有什么区别?

数组和链表是两种底层线性存储结构,差异主要体现在内存布局、随机访问、插入删除、缓存局部性和扩容成本。队列和栈是两种抽象数据类型,差异主要体现在访问顺序和操作约束:队列先进先出,栈后进先出。高质量回答要把这两层概念分开:数组和链表是实现材料,队列和栈是使用规则,队列和栈都可以用数组或链表实现。

堆上的元素满了会发生什么?

JVM 堆满通常指堆内存中可用于对象分配的空间不足。对象分配失败后,虚拟机会先尝试触发 Young GC 或 Full GC 回收空间;如果回收后仍无法满足分配,或者老年代晋升失败、连续 GC 效率过低,就可能抛出 OutOfMemoryError。回答时要围绕对象分配、GC 尝试、晋升失败、OOM 类型、排查与预防展开,不要误讲成优先队列里的堆元素满了。

数组和链表有什么区别?

数组和链表都是线性表,但底层组织方式不同:数组用连续内存存放元素,链表用离散节点通过引用连接。这个差异决定了数组随机访问快、缓存友好,但插入删除和扩容成本可能高;链表插入删除在已定位节点时很快,但查找慢、缓存局部性差、额外指针开销大。工程上不能只背复杂度,要说明复杂度成立的前提,并结合 Java 的 ArrayList 和 LinkedList 对照。

同题还出现在 1 个公司岗位

红黑树和平衡二叉树的区别?

红黑树和平衡二叉树都是为了避免普通二叉搜索树退化成链表而设计的自平衡二叉搜索树,核心区别在于平衡标准和维护成本。面试中说的平衡二叉树通常特指 AVL 树:它要求每个节点左右子树高度差最多为 1,平衡非常严格,所以查询路径更短;红黑树用颜色规则约束黑色节点数量和红色节点相邻关系,允许一定程度的不完全平衡,因此插入、删除时旋转和调整更少,更适合频繁更新的工程场景。

MySQL 底层数据结构?

MySQL 底层数据结构在 InnoDB 中主要围绕“页、B+树索引、聚簇索引、二级索引、Buffer Pool、事务日志”展开。真正决定查询性能的不是某一个抽象结构,而是这些结构如何协同:数据按页组织,索引以 B+树维护有序访问路径,主键索引叶子节点保存完整行记录,二级索引叶子节点保存主键值,内存中的 Buffer Pool 缓存热点页,变更再通过 redo log、undo log 等机制保证事务与崩溃恢复。理解这些内容,才能解释为什么 MySQL 不直接使用普通二叉树、红黑树或单纯哈希表作为主要索引结构。

JVM中的【堆】是用什么数据结构来实现的?

JVM 中的堆不是二叉堆、最大堆、最小堆这种数据结构,而是 JVM 运行时用于存放对象实例和数组的一块共享内存区域。它的具体组织方式取决于垃圾收集器:可能按年轻代、老年代划分,也可能按 Region 管理;对象分配通常依赖 TLAB、指针碰撞、空闲列表等机制,而对象回收依赖可达性分析和 GC 元数据。

如果要用线程安全的数据结构,有什么替代方案?

使用线程安全数据结构时,核心不是简单把 ArrayList、HashMap 换成带锁版本,而是先判断共享状态是否真的必须共享,再按读写比例、是否需要阻塞、是否需要顺序、是否有复合操作一致性来选型。Java 中常见替代方案包括 ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue、ConcurrentLinkedQueue、同步包装器、不可变快照、ThreadLocal、分段锁、Actor 或消息队列串行化,以及在跨进程场景下使用数据库或缓存的原子能力。

哈希冲突怎么解决?

哈希冲突是指不同 key 经过哈希函数计算后落到同一个桶或同一数组位置。回答时不能只背方法名,要先说明冲突不可完全避免,再按数据结构设计思路展开:优化哈希函数、选择冲突处理策略、控制负载因子、必要时扩容,并结合 Java HashMap 的链表转红黑树说明工程实践。

最大连续子数组和如何求解?

最大连续子数组和如何求解?这道腾讯牛客题的关键是围绕“最大连续子数组和 Kadane 动态规划”讲清概念、机制、取舍和边界。最大连续子数组和常用 Kadane 算法。定义 current 表示以当前位置结尾的最大连续和,best 表示全局最大值;遍历每个数时,current = max(x, current + x),再更新 best = max(best, current)。

数组和链表的区别?

数组和链表的区别?这道腾讯牛客题的关键是围绕“数组与链表复杂度对比”讲清概念、机制、取舍和边界。数组和链表的核心差异是存储布局。数组连续存储,支持按下标 O(1) 随机访问;链表节点离散,通过指针连接,查找第 k 个节点通常 O(n),但已知前驱节点时插入删除可以 O(1)。

链表和数组查找、删除的时间复杂度?

链表和数组查找、删除的时间复杂度?这道腾讯牛客题的关键是围绕“数组与链表复杂度对比”讲清概念、机制、取舍和边界。数组和链表的核心差异是存储布局。数组连续存储,支持按下标 O(1) 随机访问;链表节点离散,通过指针连接,查找第 k 个节点通常 O(n),但已知前驱节点时插入删除可以 O(1)。

二分查找时如何避免 int 型 mid 溢出?

二分查找时如何避免 int 型 mid 溢出?这道腾讯牛客题的关键是围绕“二分查找 mid 溢出处理”讲清概念、机制、取舍和边界。二分查找中如果用 (left + right) / 2 计算 mid,当 left 和 right 都很大时可能发生整数溢出。更稳的写法是 left + (right - left) / 2,或在语言允许时使用无符号右移/更大整数类型。

快排与归并排序的区别?

快排与归并排序的区别?这道腾讯牛客题的关键是围绕“快速排序与归并排序对比”讲清概念、机制、取舍和边界。快速排序和归并排序都能做到平均 O(n log n),但思路和工程取舍不同。快排通过 partition 原地划分再递归子区间,平均快、缓存友好但通常不稳定,最坏可能 O(n^2);归并排序先递归拆分再合并有序段,稳定且最坏 O(n log n),但通常需要 O(n) 额外空间。

如何判断一个链表是否有环?

如何判断一个链表是否有环?这道腾讯牛客题的关键是围绕“链表判环与快慢指针”讲清概念、机制、取舍和边界。判断链表是否有环,常用 Floyd 快慢指针。慢指针每次走一步,快指针每次走两步;如果链表有环,快指针最终会在环内追上慢指针;如果无环,快指针会先走到 null。

C++的vector跟Java的ArrayList的区别?

C++的vector跟Java的ArrayList的区别?这道腾讯牛客题的关键是围绕“C++ vector 与 Java ArrayList 对比”讲清概念、机制、取舍和边界。C++ vector 和 Java ArrayList 都是动态数组,但 vector 存放的是元素本身并通过模板在编译期确定类型;ArrayList 底层是 Object[] 引用数组,泛型有类型擦除,基本类型需要装箱成对象。

如何判断单链表是否成环?

如何判断单链表是否成环?这道腾讯牛客题的关键是围绕“链表判环与快慢指针”讲清概念、机制、取舍和边界。判断链表是否有环,常用 Floyd 快慢指针。慢指针每次走一步,快指针每次走两步;如果链表有环,快指针最终会在环内追上慢指针;如果无环,快指针会先走到 null。

Redis 有哪些数据结构?

Redis 有哪些数据结构?这道腾讯牛客题的关键是围绕“Redis 数据结构与底层编码”讲清概念、机制、取舍和边界。Redis 常用对外数据结构包括 String、List、Hash、Set、ZSet、Bitmap、HyperLogLog、Geo 和 Stream。回答时还要区分对外类型和底层编码,例如 SDS、listpack、quicklist、dict、intset 和 skiplist。

动态规划与贪心有什么区别?

动态规划与贪心有什么区别?这道腾讯牛客题的关键是围绕“动态规划与贪心区别”讲清概念、机制、取舍和边界。动态规划通过状态表保存子问题结果,依靠状态转移枚举可能选择;贪心每一步只做当前最优选择,并且必须能证明局部最优能导向全局最优。

Redis 的常见数据结构有哪些?

Redis 的常见数据结构有哪些?这道腾讯牛客题的关键是围绕“Redis 数据结构与底层编码”讲清概念、机制、取舍和边界。Redis 常用对外数据结构包括 String、List、Hash、Set、ZSet、Bitmap、HyperLogLog、Geo 和 Stream。回答时还要区分对外类型和底层编码,例如 SDS、listpack、quicklist、dict、intset 和 skiplist。

什么是动态规划?

什么是动态规划?这道腾讯牛客题的关键是围绕“动态规划定义与解题框架”讲清概念、机制、取舍和边界。动态规划适合具有最优子结构和重叠子问题的问题。回答时要讲清状态定义、转移方程、初始化、遍历顺序和结果位置,而不是先展开 DP 与贪心对比。

链表如何插入节点?

链表如何插入节点?这道腾讯牛客题的关键是围绕“链表节点插入流程”讲清概念、机制、取舍和边界。链表插入节点的核心是先保存后继,再改新节点和前驱的指针。单链表在已知前驱节点 prev 时,可以让 newNode.next = prev.next,再让 prev.next = newNode。

当文件无法一次全部加载内存时,如何对大文件内容排序?

当文件无法一次全部加载内存时,如何对大文件内容排序?这道腾讯牛客题的关键是围绕“大文件外部排序”讲清概念、机制、取舍和边界。大文件无法一次加载内存时,用外部排序:按内存上限分块读取,每块在内存中排序后写成临时有序 run,再用 k 路归并把多个有序 run 合成最终有序文件。