Skip to content

项目算法索引 ​

这里按问题类型整理项目中的算法实现。每行的 高亮文字 是先记住的规则;源码路径可直接在编辑器中打开。首页的 逐步实验 适合先观察冒泡、选择、插入排序和 0/1 背包,再从这里继续看其他实现。

排序 ​

算法关键知识点时间与空间源码
冒泡排序相邻交换,每轮确定一个有序后缀;相等时不交换,稳定。O(n²),额外 O(1)src/baseSort/bubbleSort.ts、src/js/sort.js
优化冒泡每轮重新记录是否交换;整轮无交换即可结束,最好 O(n)。最坏 O(n²),额外 O(1)src/js/sort.js 的 bubbleSort2
选择排序扫描未排序区间的最小值,每轮最多交换一次;比较仍为 n(n−1)/2 次,通常不稳定。O(n²),额外 O(1)src/baseSort/selectionSort.ts、src/js/sort.js
插入排序暂存当前值、右移更大的值;有序前缀逐轮扩大,相等时不移动,稳定。最好 O(n),最坏 O(n²),额外 O(1)src/baseSort/insertionSort.ts、src/js/sort.js
快速排序按基准值分区,递归处理左右两边;这里选首元素,已排序输入会退化。平均 O(n log n),最坏 O(n²)src/baseSort/quickSort.ts、src/js/sort.js
堆排序最大堆根节点是当前最大值,与末尾交换后缩小堆。O(n log n),递归栈 O(log n)src/js/sort.js 的 heapSort
归并排序先分后合;合并相等值时先取左边,保持稳定。O(n log n),额外 O(n)src/js/sort.js 的 mergeSort
希尔排序逐步缩小间隔,最后用 gap=1 完成插入排序;不稳定。此间隔序列最坏 O(n²),额外 O(1)src/js/sort.js 的 shellSort

排序数组允许重复值和负数。src/baseSort 可直接用于手写练习,首页的逐步演示独立运行,练习未完成也不影响展示;src/js/sort.js 保留多种方法,便于比较原位排序与返回新数组的做法。

动态规划与数值 ​

算法关键知识点边界与代价源码
0/1 背包(二维)选或不选第 i 件,只从上一行转移。不要求装满;O(nC) 时间和空间src/js/dp2.js 的 knapsack
0/1 背包(一维)容量倒序,确保 dp[c−w] 尚未使用当前物品。同一件只能选一次;O(nC) 时间、O(C) 空间src/js/dp2.js 的 knapsack2
最长严格递增子序列dp[i] 必须以第 i 项结尾;答案是所有状态的最大值。相等不算递增;空数组返回 0;O(n²)src/js/dp2.js 的 getLongSeries
爬楼梯最后一步来自前一级或前两级,两种走法相加。0 级视为一种空走法;O(n) 时间、O(1) 空间src/js/dp1.js 的 climbStairs
最少硬币数不可达状态为 Infinity;每种硬币可重复使用。无解返回 −1;O(金额 × 面额数)src/js/dp1.js 的 getCoinCount、coinChange
硬币组合数先硬币、后金额正序,避免把不同顺序重复计数。金额 0 有一种空组合;O(金额 × 面额数)src/js/dp1.js 的 getCoinList
斐波那契只依赖前两项;朴素递归重复计算,记忆化和迭代可降到 O(n)。f(0)=0;朴素递归限 0~40,其余实现精确计算 0~78src/js/fab.js、src/ts/fab.ts
每堆取 1 或 2 枚各堆独立,答案是 Σ ceil(每堆数量 / 2)。空列表为 0;O(堆数)src/js/xCoins.js
大数相加从低位逐位相加并传递进位,不把整个输入转成 Number。只接受非空十进制数字串;O(较长输入位数)src/ts/bigNumberPure.ts、src/ts/bigNumber.ts

背包中的 dp[c] 表示“容量不超过 c 的最大价值”。正序更新会读到本轮刚写过的状态,等价于允许重复选当前物品;首页实验可切换方向直接对照。

数据、搜索与结构 ​

算法关键知识点边界或限制源码
路径建树先建所有前缀节点,再按 parentId 连接;重复路径只建一次。叶子节点 children 为 nullsrc/js/arrayToTree.js
关键词邻行搜索按原文行号选前、当前、后一行,再按行内容去重。忽略空行;保持原文顺序src/js/findWord.js 的 findWord
流式关键词搜索记住上一行并等待下一行;末尾无换行时要冲洗缓冲区。getResult() 冲洗末尾片段src/js/findWord.js 的 StreamWordFind
深拷贝递归前登记副本,解决循环引用和共享引用。支持普通对象、数组、日期、正则、Map、Set 和二进制视图;函数保持引用src/deepCopy.js、src/ts/deepCopy.ts
原型链判断逐级检查 prototype;原始值不是实例。右侧必须是有效构造函数src/js/instanceof.js

异步与时间控制 ​

算法关键知识点失败或边界行为源码
Promise.all结果按输入位置排列,与完成顺序无关。任一拒绝则整体拒绝;空列表得到 []src/promiseAll.js
并发任务队列同时运行数不超过上限,完成一个再启动下一个;结果按加入顺序排列。失败也释放槽位,空闲后向调用者报错src/js/concurrentReq.js、src/js/reqControl.js、src/ts/reqControl.ts
防抖最后一次调用重置计时,安静期后执行。保留最后一次的参数和 thissrc/js/throttle-debounce.js、src/ts/debounce.ts
立即防抖首次立即执行,窗口内的新调用合并为尾沿一次。尾沿使用最后一次的参数src/js/throttle-debounce.js 的 debounceImmediate
前沿节流每个时间窗口只执行首次调用。窗口内其他调用跳过src/js/throttle-debounce.js、src/ts/throttle.ts
定时器节流首次调用安排延后执行。等待期间的调用跳过src/js/throttle-debounce.js 的 throttleTimer
尾沿节流窗口末尾使用最后一次调用,保证持续触发时最后的值可见。可关闭尾沿;使用最后的参数和 thissrc/js/throttle-debounce.js 的 throttleTrailing
漂移补偿定时器按计划时间安排下一次触发,错过的周期直接跳过。返回取消函数,防止定时器继续运行src/js/timer.js

函数组合与事件 ​

算法关键知识点源码
柯里化与分批求和每条部分调用链独立保存参数,避免不同调用相互污染。src/js/curry.js、src/js/curry2.js、src/js/curry3.js
函数组合从右向左执行;没有函数时直接返回初始值。src/js/curry4.js 的 compose
事件总线once 回调执行前先取消订阅,递归触发也只运行一次。src/js/eventBus.js
call、apply、bind、new参数传递、绑定 this 与构造调用是不同语义;这里用 Reflect 和原生 bind 保留完整构造行为。src/js/_apply_call_new.js、src/ts/call.ts、src/ts/apply.ts、src/ts/bindNew.ts、src/ts/new.ts
模块加载模块先进入缓存,再执行工厂,循环依赖才能读到部分导出;加载失败会移除缓存。src/js/imitateLoad.js 的 createModuleLoader

practice/algorithms.ts 仍是留给自己动手的练习区;它的四个空实现不会影响上面这些参考实现。