379 lines
8.2 KiB
Markdown
379 lines
8.2 KiB
Markdown
# 数据结构与算法
|
||
|
||
## 1. 链表
|
||
|
||
> **场景**:操作历史记录(浏览器前进后退)、LRU 缓存淘汰、撤销重做功能、音乐播放列表。
|
||
> **解决**:频繁插入/删除场景下数组性能差的问题,O(1) 插入删除。
|
||
|
||
### 反转链表
|
||
|
||
```js
|
||
function reverseList(head) {
|
||
let prev = null, curr = head;
|
||
while (curr) {
|
||
const next = curr.next;
|
||
curr.next = prev;
|
||
prev = curr;
|
||
curr = next;
|
||
}
|
||
return prev;
|
||
}
|
||
```
|
||
|
||
### 环形链表判断
|
||
|
||
```js
|
||
function hasCycle(head) {
|
||
let slow = head, fast = head;
|
||
while (fast?.next) {
|
||
slow = slow.next;
|
||
fast = fast.next.next;
|
||
if (slow === fast) return true;
|
||
}
|
||
return false;
|
||
}
|
||
```
|
||
|
||
### 合并有序链表
|
||
|
||
```js
|
||
function mergeTwoLists(l1, l2) {
|
||
const dummy = { next: null };
|
||
let curr = dummy;
|
||
while (l1 && l2) {
|
||
if (l1.val <= l2.val) {
|
||
curr.next = l1;
|
||
l1 = l1.next;
|
||
} else {
|
||
curr.next = l2;
|
||
l2 = l2.next;
|
||
}
|
||
curr = curr.next;
|
||
}
|
||
curr.next = l1 || l2;
|
||
return dummy.next;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 二叉树
|
||
|
||
> **场景**:DOM 树遍历、文件目录结构、组织架构图、表达式解析、前端路由匹配。
|
||
> **解决**:层级数据的存储与高效查找,遍历、搜索与路径问题。
|
||
|
||
### 遍历(前中后序)
|
||
|
||
```js
|
||
// 前序:根-左-右
|
||
const preorder = (root, res = []) => {
|
||
if (!root) return res;
|
||
res.push(root.val);
|
||
preorder(root.left, res);
|
||
preorder(root.right, res);
|
||
return res;
|
||
};
|
||
|
||
// 中序:左-根-右
|
||
const inorder = (root, res = []) => {
|
||
if (!root) return res;
|
||
inorder(root.left, res);
|
||
res.push(root.val);
|
||
inorder(root.right, res);
|
||
return res;
|
||
};
|
||
|
||
// 后序:左-右-根
|
||
const postorder = (root, res = []) => {
|
||
if (!root) return res;
|
||
postorder(root.left, res);
|
||
postorder(root.right, res);
|
||
res.push(root.val);
|
||
return res;
|
||
};
|
||
```
|
||
|
||
### 求最大深度
|
||
|
||
```js
|
||
const maxDepth = root => {
|
||
if (!root) return 0;
|
||
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
|
||
};
|
||
```
|
||
|
||
### 路径和
|
||
|
||
```js
|
||
function hasPathSum(root, targetSum) {
|
||
if (!root) return false;
|
||
if (!root.left && !root.right) return targetSum === root.val;
|
||
return hasPathSum(root.left, targetSum - root.val)
|
||
|| hasPathSum(root.right, targetSum - root.val);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 栈与队列
|
||
|
||
> **场景**:栈用于括号匹配、撤销操作、函数调用栈;队列用于任务调度、消息队列、BFS 广度优先搜索。
|
||
> **解决**:先进后出/先进先出的数据操作顺序控制。
|
||
|
||
### 用栈实现队列
|
||
|
||
```js
|
||
class MyQueue {
|
||
constructor() {
|
||
this.inStack = [];
|
||
this.outStack = [];
|
||
}
|
||
|
||
push(x) { this.inStack.push(x); }
|
||
|
||
pop() {
|
||
if (!this.outStack.length) {
|
||
while (this.inStack.length) this.outStack.push(this.inStack.pop());
|
||
}
|
||
return this.outStack.pop();
|
||
}
|
||
|
||
peek() {
|
||
if (!this.outStack.length) {
|
||
while (this.inStack.length) this.outStack.push(this.inStack.pop());
|
||
}
|
||
return this.outStack[this.outStack.length - 1];
|
||
}
|
||
|
||
empty() { return !this.inStack.length && !this.outStack.length; }
|
||
}
|
||
```
|
||
|
||
### 有效的括号
|
||
|
||
```js
|
||
function isValid(s) {
|
||
const map = { ')': '(', ']': '[', '}': '{' };
|
||
const stack = [];
|
||
for (const c of s) {
|
||
if (map[c]) {
|
||
if (stack.pop() !== map[c]) return false;
|
||
} else {
|
||
stack.push(c);
|
||
}
|
||
}
|
||
return !stack.length;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 哈希表
|
||
|
||
> **场景**:快速查找(用户ID查询)、统计词频、数据去重、分组操作。
|
||
> **解决**:O(1) 时间复杂度的键值对存储和查找,避免线性遍历。
|
||
|
||
### 两数之和
|
||
|
||
```js
|
||
function twoSum(nums, target) {
|
||
const map = new Map();
|
||
for (let i = 0; i < nums.length; i++) {
|
||
const diff = target - nums[i];
|
||
if (map.has(diff)) return [map.get(diff), i];
|
||
map.set(nums[i], i);
|
||
}
|
||
return [];
|
||
}
|
||
```
|
||
|
||
### 字母异位词分组
|
||
|
||
```js
|
||
function groupAnagrams(strs) {
|
||
const map = new Map();
|
||
for (const s of strs) {
|
||
const key = [...s].sort().join('');
|
||
map.set(key, (map.get(key) || []).concat(s));
|
||
}
|
||
return [...map.values()];
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 排序算法
|
||
|
||
> **场景**:商品价格/销量排序、排行榜、数据可视化预处理。
|
||
> **解决**:无序数据有序化,理解分治思想(快排、归并)是算法基础。
|
||
|
||
### 快速排序
|
||
|
||
```js
|
||
function quickSort(arr) {
|
||
if (arr.length <= 1) return arr;
|
||
const pivot = arr[Math.floor(arr.length / 2)];
|
||
const left = arr.filter(x => x < pivot);
|
||
const middle = arr.filter(x => x === pivot);
|
||
const right = arr.filter(x => x > pivot);
|
||
return [...quickSort(left), ...middle, ...quickSort(right)];
|
||
}
|
||
```
|
||
|
||
### 归并排序
|
||
|
||
```js
|
||
function mergeSort(arr) {
|
||
if (arr.length <= 1) return arr;
|
||
const mid = Math.floor(arr.length / 2);
|
||
const left = mergeSort(arr.slice(0, mid));
|
||
const right = mergeSort(arr.slice(mid));
|
||
return merge(left, right);
|
||
}
|
||
|
||
function merge(left, right) {
|
||
const result = [];
|
||
let i = 0, j = 0;
|
||
while (i < left.length && j < right.length) {
|
||
result.push(left[i] < right[j] ? left[i++] : right[j++]);
|
||
}
|
||
return result.concat(left.slice(i), right.slice(j));
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 二分查找
|
||
|
||
> **场景**:有序列表快速定位(分页跳转)、版本号查找、IP 地址归属地查询、猜数字游戏。
|
||
> **解决**:在有序数据中 O(log n) 时间复杂度快速查找,比线性查找效率高很多。
|
||
|
||
### 基础二分查找
|
||
|
||
```js
|
||
function binarySearch(arr, target) {
|
||
let left = 0, right = arr.length - 1;
|
||
while (left <= right) {
|
||
const mid = Math.floor((left + right) / 2);
|
||
if (arr[mid] === target) return mid;
|
||
arr[mid] < target ? (left = mid + 1) : (right = mid - 1);
|
||
}
|
||
return -1;
|
||
}
|
||
```
|
||
|
||
### 旋转数组查找
|
||
|
||
```js
|
||
function searchRotated(nums, target) {
|
||
let left = 0, right = nums.length - 1;
|
||
while (left <= right) {
|
||
const mid = Math.floor((left + right) / 2);
|
||
if (nums[mid] === target) return mid;
|
||
|
||
// 左半边有序
|
||
if (nums[left] <= nums[mid]) {
|
||
if (target >= nums[left] && target < nums[mid]) right = mid - 1;
|
||
else left = mid + 1;
|
||
} else {
|
||
// 右半边有序
|
||
if (target > nums[mid] && target <= nums[right]) left = mid + 1;
|
||
else right = mid - 1;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 斐波那契数列
|
||
|
||
> **场景**:算法入门经典题、理解递归与动态规划思想、缓存优化演示、爬楼梯问题变种。
|
||
> **解决**:求第 n 位斐波那契数(F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2))。
|
||
|
||
### 方法一:普通递归(不推荐)
|
||
|
||
```js
|
||
// 时间复杂度 O(2^n),存在大量重复计算
|
||
function fib(n) {
|
||
if (n <= 1) return n;
|
||
return fib(n - 1) + fib(n - 2);
|
||
}
|
||
```
|
||
|
||
### 方法二:记忆化递归
|
||
|
||
```js
|
||
// 时间复杂度 O(n),空间复杂度 O(n)
|
||
function fib(n, memo = {}) {
|
||
if (n <= 1) return n;
|
||
if (memo[n]) return memo[n];
|
||
return memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
|
||
}
|
||
```
|
||
|
||
### 方法三:动态规划
|
||
|
||
```js
|
||
// 时间复杂度 O(n),空间复杂度 O(n)
|
||
function fib(n) {
|
||
if (n <= 1) return n;
|
||
const dp = [0, 1];
|
||
for (let i = 2; i <= n; i++) {
|
||
dp[i] = dp[i - 1] + dp[i - 2];
|
||
}
|
||
return dp[n];
|
||
}
|
||
```
|
||
|
||
### 方法四:空间优化(推荐)
|
||
|
||
```js
|
||
// 时间复杂度 O(n),空间复杂度 O(1)
|
||
function fib(n) {
|
||
if (n <= 1) return n;
|
||
let prev = 0, curr = 1;
|
||
for (let i = 2; i <= n; i++) {
|
||
[prev, curr] = [curr, prev + curr];
|
||
}
|
||
return curr;
|
||
}
|
||
```
|
||
|
||
### 方法五:矩阵快速幂(大数优化)
|
||
|
||
```js
|
||
// 时间复杂度 O(log n),适合求极大位数
|
||
function fib(n) {
|
||
if (n <= 1) return n;
|
||
|
||
const multiply = (a, b) => [
|
||
[a[0][0] * b[0][0] + a[0][1] * b[1][0], a[0][0] * b[0][1] + a[0][1] * b[1][1]],
|
||
[a[1][0] * b[0][0] + a[1][1] * b[1][0], a[1][0] * b[0][1] + a[1][1] * b[1][1]]
|
||
];
|
||
|
||
const power = (m, p) => {
|
||
let result = [[1, 0], [0, 1]]; // 单位矩阵
|
||
while (p > 0) {
|
||
if (p & 1) result = multiply(result, m);
|
||
m = multiply(m, m);
|
||
p >>= 1;
|
||
}
|
||
return result;
|
||
};
|
||
|
||
const matrix = [[1, 1], [1, 0]];
|
||
return power(matrix, n - 1)[0][0];
|
||
}
|
||
```
|
||
|
||
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|
||
|------|-----------|-----------|----------|
|
||
| 普通递归 | O(2^n) | O(n) | 仅理解思想 |
|
||
| 记忆化递归 | O(n) | O(n) | 面试常考 |
|
||
| 动态规划 | O(n) | O(n) | 面试常考 |
|
||
| 空间优化 | O(n) | O(1) | **推荐** |
|
||
| 矩阵快速幂 | O(log n) | O(1) | 大数/竞赛 |
|
||
|