面试题库
整理各类技术面试题目,包含解题思路和参考答案。共收录 6 道题目。
简单算法#数组#哈希表两数之和
两数之和
题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。
解题思路
使用哈希表存储已遍历的元素及其索引。遍历数组时,检查 target - nums[i] 是否在哈希表中,如果存在则返回两个索引;否则将当前元素加入哈希表。时间复杂度 O(n),空间复杂度 O(n)。
参考代码
function twoSum(nums: number[], target: number): number[] {
const map = new Map<number, number>();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement)!, i];
}
map.set(nums[i], i);
}
return [];
}中等前端#JavaScript#Promise实现一个 Promise.all
实现一个 Promise.all
题目描述
请实现一个 Promise.all 方法,接收一个 Promise 数组,返回一个新的 Promise。当所有 Promise 都成功时,返回所有结果的数组;当任一 Promise 失败时,返回第一个失败的原因。
解题思路
创建一个结果数组和计数器,遍历所有 Promise,使用 Promise.resolve 包装确保兼容非 Promise 值。成功时将结果存入对应位置并增加计数,当计数等于总数时 resolve 结果数组。任一失败则直接 reject。
参考代码
function promiseAll<T>(promises: Promise<T>[]): Promise<T[]> {
return new Promise((resolve, reject) => {
const results: T[] = [];
let completed = 0;
if (promises.length === 0) {
resolve(results);
return;
}
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then((value) => {
results[index] = value;
completed++;
if (completed === promises.length) {
resolve(results);
}
})
.catch(reject);
});
});
}中等算法#设计#哈希表LRU 缓存机制
LRU 缓存机制
题目描述
设计和实现一个 LRU (最近最少使用) 缓存机制。实现 LRUCache 类:get(key) 如果关键字存在于缓存中,则返回关键字的值,否则返回 -1;put(key, value) 如果关键字已经存在,则变更其数据值,如果关键字不存在则插入该组数据。当缓存容量达到上限时,应该在写入新数据之前删除最久未使用的数据值。
解题思路
使用哈希表 + 双向链表实现。哈希表提供 O(1) 的查找,双向链表维护访问顺序。每次 get/put 操作都将对应节点移到链表头部,当容量满时删除链表尾部节点。JavaScript 中可以用 Map 保持插入顺序来简化实现。
参考代码
class LRUCache {
private capacity: number;
private cache: Map<number, number>;
constructor(capacity: number) {
this.capacity = capacity;
this.cache = new Map();
}
get(key: number): number {
if (!this.cache.has(key)) return -1;
const value = this.cache.get(key)!;
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
put(key: number, value: number): void {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}中等前端#React#虚拟DOM解释 React 的虚拟 DOM 原理
解释 React 的虚拟 DOM 原理
题目描述
请解释 React 虚拟 DOM 的工作原理,以及它如何提高性能?Diff 算法是如何工作的?
解题思路
虚拟 DOM 是真实 DOM 的 JavaScript 对象表示。当状态变化时,React 创建新的虚拟 DOM 树,通过 Diff 算法与旧树比较,计算出最小变更集,然后批量更新真实 DOM。Diff 算法采用三个策略优化:1) 只比较同层节点;2) 不同类型节点直接替换;3) 通过 key 属性标识同一节点。这避免了频繁的 DOM 操作,提升了性能。
困难后端#MySQL#索引数据库索引原理
数据库索引原理
题目描述
请解释 MySQL 中 B+ 树索引的原理。为什么选择 B+ 树而不是二叉树或 B 树?聚簇索引和非聚簇索引有什么区别?
解题思路
B+ 树是多路平衡搜索树,特点:1) 非叶子节点只存索引,叶子节点存数据,减少 IO 次数;2) 叶子节点形成有序链表,支持范围查询;3) 树高度低(通常3-4层),查询效率稳定。相比二叉树,B+ 树更矮胖,减少磁盘 IO;相比 B 树,B+ 树叶子节点链表更适合范围查询。聚簇索引的叶子节点存储完整数据行(InnoDB 主键),非聚簇索引叶子节点存储主键值,需要回表查询。
中等前端#JavaScript#深拷贝实现深拷贝
实现深拷贝
题目描述
请实现一个深拷贝函数,能够正确处理各种数据类型,包括对象、数组、Date、RegExp、循环引用等。
解题思路
使用递归遍历对象的所有属性。需要处理的情况:1) 基本类型直接返回;2) Date 和 RegExp 特殊处理;3) 使用 WeakMap 缓存已拷贝对象解决循环引用;4) 遍历对象/数组的所有属性递归拷贝。
参考代码
function deepClone<T>(obj: T, cache = new WeakMap()): T {
// 基本类型
if (obj === null || typeof obj !== 'object') return obj;
// 处理循环引用
if (cache.has(obj as object)) return cache.get(obj as object);
// 处理 Date
if (obj instanceof Date) return new Date(obj.getTime()) as T;
// 处理 RegExp
if (obj instanceof RegExp) return new RegExp(obj) as T;
// 处理数组和对象
const clone = Array.isArray(obj) ? [] : {} as T;
cache.set(obj as object, clone);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
(clone as any)[key] = deepClone((obj as any)[key], cache);
}
}
return clone;
}