一、数据结构核心面试题与解析
(一)树与查找结构
1. 二叉排序树(BST)相关问题
面试题1:二叉排序树与快速排序的联系
联系解析:
- 分治思想同源:BST的插入/查找类似快速排序的分区操作(左子树<根<右子树 vs 快排的基准值分区);
- 时间复杂度关联:BST的平均查找复杂度O(log n)与快排的平均时间复杂度O(n log n)均依赖数据分布;
- 空间结构映射:BST的树形结构可视为快排递归调用栈的可视化(每个节点对应一次分区)。
2. 平衡二叉树(AVL树)
面试题2:AVL树的失衡调整方式
四种调整类型:
- LL型(左左失衡):右旋转
// 右旋转函数 private Node rightRotate(Node root) { Node leftChild = root.left; root.left = leftChild.right; leftChild.right = root; root.height = max(getHeight(root.left), getHeight(root.right)) + 1; leftChild.height = max(getHeight(leftChild.left), getHeight(root)) + 1; return leftChild; }
- RR型(右右失衡):左旋转(与LL型对称);
- LR型(左右失衡):先左旋转左子树,再右旋转根节点;
- RL型(右左失衡):先右旋转右子树,再左旋转根节点。
核心逻辑:通过旋转调整子树高度,确保平衡因子绝对值≤1,旋转后需更新节点高度。
3. 红黑树
面试题3:红黑树的五条性质
性质总结:
- 每个节点要么是红,要么是黑;
- 根节点和叶子节点(NIL节点)是黑色;
- 红色节点的两个子节点必为黑色(红节点不能相邻);
- 从任一节点到其每个叶子节点的所有路径包含相同数量的黑色节点(黑高平衡);
- 新插入节点默认红色,通过重新着色和旋转维持性质。
应用场景:Java的TreeMap
和ConcurrentSkipListMap
底层使用红黑树,相比AVL树,红黑树牺牲部分平衡性换取更低的旋转开销,适合频繁插入/删除的场景。
(二)哈希表与二叉排序树对比
面试题4:对比二叉排序树和哈希表
维度 | 二叉排序树 | 哈希表 |
---|---|---|
查找复杂度 | 平均O(log n),最坏O(n) | 平均O(1),最坏O(n) |
数据顺序 | 支持有序遍历(中序遍历) | 无序,需额外排序 |
适用场景 | 范围查询(如查询区间元素) | 键值对快速存取 |
冲突处理 | 无冲突问题 | 需处理哈希冲突(开放寻址/链地址法) |
典型实现 | Java的TreeSet | Java的HashMap |
二、经典算法与大厂高频题
(一)查找算法与生活案例
面试题5:生活中的查找场景与算法选择
场景 | 需求 | 数据结构 | 算法 | 复杂度 |
---|---|---|---|---|
图书馆书目检索 | 书名快速定位 | 哈希表/二叉树 | 哈希查找/二分查找 | O(1)/O(log n) |
电商商品搜索 | 关键词模糊匹配 | 前缀树(Trie) | 前缀匹配 | O(k) |
通讯录联系人查找 | 姓名首字母快速导航 | 二叉排序树 | 中序遍历 | O(log n) |
词典单词拼写检查 | 单词是否存在 | 哈希集合 | 哈希查找 | O(1) |
(二)Top-k问题解法全解析
面试题6:Top-k解法分情况讨论
分类解法:
- 数据规模小(内存可容纳):
- 排序法:排序后取前k个元素,时间复杂度O(n log n)。
// 快速排序后取前k大元素 public int[] topK(int[] nums, int k) { Arrays.sort(nums); int[] result = new int[k]; System.arraycopy(nums, nums.length - k, result, 0, k); return result; }
- 快速选择(QuickSelect):基于快排的分区思想,平均O(n),最坏O(n²)。
public int findKthLargest(int[] nums, int k) { return quickSelect(nums, 0, nums.length - 1, nums.length - k); } private int quickSelect(int[] nums, int low, int high, int k) { int pivotIndex = partition(nums, low, high); if (pivotIndex == k) return nums[pivotIndex]; return pivotIndex < k ? quickSelect(nums, pivotIndex + 1, high, k) : quickSelect(nums, low, pivotIndex - 1, k); }
- 排序法:排序后取前k个元素,时间复杂度O(n log n)。
- 数据规模大(需外部存储):
- 堆排序:
- 最小堆(求Top-k大):构建k大小的最小堆,遍历数组维护堆,时间O(n log k)。
public int[] topK(int[] nums, int k) { PriorityQueue<Integer> minHeap = new PriorityQueue<>(); for (int num : nums) { minHeap.offer(num); if (minHeap.size() > k) minHeap.poll(); } int[] result = new int[k]; for (int i = 0; i < k; i++) result[i] = minHeap.poll(); return result; }
- 分治法:将数据分块排序后合并,适用于分布式场景(如MapReduce)。
- 堆排序:
(三)排序场景与算法选择
面试题7:生活中的排序场景
场景 | 需求 | 算法 | 优化点 |
---|---|---|---|
电商商品排序 | 价格/销量多维度排序 | 归并排序/快速排序 | 自定义比较器 |
考试成绩排名 | 分数从高到低排序 | 堆排序 | 稳定性要求(相同分数保留原始顺序) |
图书馆书架整理 | 书籍按编号递增排列 | 插入排序 | 局部有序时效率高 |
大数据日志排序 | 海量数据磁盘排序 | 外部排序(归并) | 减少I/O次数 |
三、Java高频算法题分类解析(附LeetCode真题)
(一)数组与字符串
1. 两数之和(LeetCode 1)
解法:哈希表记录互补值,O(n)时间。
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i =