算法
一、排序算法
1. 快速排序
问题:快速排序
答案: 核心回答:快速排序使用分治策略,选择基准元素分区递归排序。
代码示例:
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)];
}
// in-place 版本
function quickSortInPlace(arr, low = 0, high = arr.length - 1) {
if (low < high) {
const pi = partition(arr, low, high);
quickSortInPlace(arr, low, pi - 1);
quickSortInPlace(arr, pi + 1, high);
}
return arr;
}
function partition(arr, low, high) {
const pivot = arr[high];
let i = low - 1;
for (let j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
return i + 1;
}
// 时间复杂度:平均 O(n log n),最坏 O(n²)
// 空间复杂度:O(log n)
2. 归并排序
问题:归并排序
答案: 核心回答:归并排序使用分治策略,将数组二分递归排序后合并。
代码示例:
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) {
if (left[i] <= right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(left.slice(i)).concat(right.slice(j));
}
// 时间复杂度:O(n log n) 稳定
// 空间复杂度:O(n)
3. 冒泡排序
问题:冒泡排序
答案: 核心回答:冒泡排序通过相邻元素比较交换,将最大元素冒泡到末尾。
代码示例:
function bubbleSort(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
let swapped = false;
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
if (!swapped) break; // 优化:提前结束
}
return arr;
}
// 时间复杂度:O(n²)
// 空间复杂度:O(1)
二、查找算法
4. 二分查找
问题:二分查找
答案: 核心回答:二分查找通过折半查找目标值,要求数组有序。
代码示例:
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 未找到
}
// 递归版本
function binarySearchRecursive(arr, target, left = 0, right = arr.length - 1) {
if (left > right) return -1;
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
return binarySearchRecursive(arr, target, mid + 1, right);
} else {
return binarySearchRecursive(arr, target, left, mid - 1);
}
}
// 时间复杂度:O(log n)
// 空间复杂度:O(1)
三、数据结构
5. 栈与队列
问题:栈与队列
答案: 核心回答:栈是 LIFO,队列是 FIFO。
代码示例:
// 栈
class Stack {
constructor() {
this.items = [];
}
push(item) {
this.items.push(item);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
}
// 队列
class Queue {
constructor() {
this.items = [];
}
enqueue(item) {
this.items.push(item);
}
dequeue() {
return this.items.shift();
}
front() {
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
}
// 循环队列
class CircularQueue {
constructor(k) {
this.k = k;
this.queue = new Array(k);
this.head = -1;
this.tail = -1;
}
enqueue(value) {
if (this.isFull()) return false;
this.tail = (this.tail + 1) % this.k;
this.queue[this.tail] = value;
if (this.head === -1) this.head = this.tail;
return true;
}
dequeue() {
if (this.isEmpty()) return false;
if (this.head === this.tail) {
this.head = -1;
this.tail = -1;
} else {
this.head = (this.head + 1) % this.k;
}
return true;
}
}
6. 链表
问题:链表
答案: 核心回答:链表是线性数据结构,通过指针连接节点。
代码示例:
class ListNode {
constructor(val) {
this.val = val;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
append(val) {
const node = new ListNode(val);
if (!this.head) {
this.head = node;
} else {
let curr = this.head;
while (curr.next) {
curr = curr.next;
}
curr.next = node;
}
this.size++;
}
remove(index) {
if (index < 0 || index >= this.size) return;
if (index === 0) {
this.head = this.head.next;
} else {
let prev = this.head;
for (let i = 0; i < index - 1; i++) {
prev = prev.next;
}
prev.next = prev.next.next;
}
this.size--;
}
reverse() {
let prev = null;
let curr = this.head;
while (curr) {
const next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
this.head = prev;
}
}
7. 哈希表
问题:哈希表
答案: 核心回答:哈希表通过哈希函数将键映射到值,实现 O(1) 查找。
代码示例:
class HashMap {
constructor(size = 100) {
this.size = size;
this.buckets = new Array(size).fill(null).map(() => []);
}
_hash(key) {
let hash = 0;
for (const char of key) {
hash = (hash * 31 + char.charCodeAt(0)) % this.size;
}
return hash;
}
set(key, value) {
const index = this._hash(key);
const bucket = this.buckets[index];
for (const [k, v] of bucket) {
if (k === key) {
bucket[bucket.indexOf([k, v])] = [key, value];
return;
}
}
bucket.push([key, value]);
}
get(key) {
const index = this._hash(key);
const bucket = this.buckets[index];
for (const [k, v] of bucket) {
if (k === key) return v;
}
return undefined;
}
delete(key) {
const index = this._hash(key);
const bucket = this.buckets[index];
for (const [k, v] of bucket) {
if (k === key) {
bucket.splice(bucket.indexOf([k, v]), 1);
return true;
}
}
return false;
}
}
四、算法思想
8. 动态规划
问题:动态规划
答案: 核心回答:动态规划通过保存子问题结果,避免重复计算。
代码示例:
// 斐波那契数列
function fibonacci(n) {
if (n <= 1) return n;
const dp = new Array(n + 1);
dp[0] = 0;
dp[1] = 1;
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
// 空间优化
function fibonacciOptimized(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;
}
// 爬楼梯
function climbStairs(n) {
if (n <= 2) return n;
let prev = 1, curr = 2;
for (let i = 3; i <= n; i++) {
[prev, curr] = [curr, prev + curr];
}
return curr;
}
// 最长公共子序列
function lcs(text1, text2) {
const m = text1.length, n = text2.length;
const dp = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (text1[i - 1] === text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
9. 贪心算法
问题:贪心算法
答案: 核心回答:贪心算法每步选择局部最优解,期望得到全局最优。
代码示例:
// 找零钱问题
function coinChange(coins, amount) {
coins.sort((a, b) => b - a);
let count = 0;
let remaining = amount;
for (const coin of coins) {
while (remaining >= coin) {
remaining -= coin;
count++;
}
}
return remaining === 0 ? count : -1;
}
// 活动选择问题
function activitySelection(activities) {
// 按结束时间排序
activities.sort((a, b) => a[1] - b[1]);
const selected = [activities[0]];
let lastEnd = activities[0][1];
for (let i = 1; i < activities.length; i++) {
if (activities[i][0] >= lastEnd) {
selected.push(activities[i]);
lastEnd = activities[i][1];
}
}
return selected;
}
10. 回溯算法
问题:回溯算法
答案: 核心回答:回溯通过尝试分步解决问题,不可行时退回上一步。
代码示例:
// 全排列
function permute(nums) {
const result = [];
function backtrack(path, used) {
if (path.length === nums.length) {
result.push([...path]);
return;
}
for (let i = 0; i < nums.length; i++) {
if (used[i]) continue;
path.push(nums[i]);
used[i] = true;
backtrack(path, used);
path.pop();
used[i] = false;
}
}
backtrack([], new Array(nums.length).fill(false));
return result;
}
// 子集
function subsets(nums) {
const result = [];
function backtrack(start, path) {
result.push([...path]);
for (let i = start; i < nums.length; i++) {
path.push(nums[i]);
backtrack(i + 1, path);
path.pop();
}
}
backtrack(0, []);
return result;
}
// N 皇后
function solveNQueens(n) {
const result = [];
const board = new Array(n).fill('.'.repeat(n));
function isValid(row, col, board) {
for (let i = 0; i < row; i++) {
if (board[i][col] === 'Q') return false;
}
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] === 'Q') return false;
}
for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (board[i][j] === 'Q') return false;
}
return true;
}
function backtrack(row, board) {
if (row === n) {
result.push(board.map(r => r.join('')));
return;
}
for (let col = 0; col < n; col++) {
if (!isValid(row, col, board)) continue;
board[row][col] = 'Q';
backtrack(row + 1, board);
board[row][col] = '.';
}
}
backtrack(0, board);
return result;
}