diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..3873dcfee2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +node_modules +template +packages/test +temp +dist +scripts +lib +coverage +.eslintrc.js +tempCodeRunnerFile.js diff --git a/.gitignore b/.gitignore index e128b69788..d7f02cd242 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ node_modules coverage .vscode .DS_Store + +temp +tempCodeRunnerFile.js diff --git a/.npmrc b/.npmrc index b6f27f1359..1d456dd784 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ engine-strict=true +registry=https://registry.npmjs.org/ diff --git a/.nvmrc b/.nvmrc index 7fd023741b..9bcccb9439 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.15.0 +v20.13.1 diff --git a/README.zh-CN.md b/README.zh-CN.md index cdef9cabea..eb0976917c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -25,7 +25,7 @@ _Read this in other languages:_ [_Tiếng Việt_](README.vi-VN.md), [_Deutsch_](README.de-DE.md) -*注意:这个项目仅用于学习和研究,**不是**用于生产环境。* +_注意:这个项目仅用于学习和研究,**不是**用于生产环境。_ ## 数据结构 @@ -33,23 +33,23 @@ _Read this in other languages:_ `B` - 初学者, `A` - 进阶 -* `B` [链表](src/data-structures/linked-list/README.zh-CN.md) -* `B` [双向链表](src/data-structures/doubly-linked-list/README.zh-CN.md) -* `B` [队列](src/data-structures/queue/README.zh-CN.md) -* `B` [栈](src/data-structures/stack/README.zh-CN.md) -* `B` [哈希表(散列)](src/data-structures/hash-table/README.zh-CN.md) -* `B` [堆](src/data-structures/heap/README.zh-CN.md) - 最大堆 & 最小堆 -* `B` [优先队列](src/data-structures/priority-queue/README.zh-CN.md) -* `A` [字典树](src/data-structures/trie/README.zh-CN.md) -* `A` [树](src/data-structures/tree/README.zh-CN.md) - * `A` [二叉查找树](src/data-structures/tree/binary-search-tree) - * `A` [AVL 树](src/data-structures/tree/avl-tree) - * `A` [红黑树](src/data-structures/tree/red-black-tree) - * `A` [线段树](src/data-structures/tree/segment-tree) - 使用 `最小/最大/总和` 范围查询示例 - * `A` [树状数组](src/data-structures/tree/fenwick-tree) (二叉索引树) -* `A` [图](src/data-structures/graph/README.zh-CN.md) (有向图与无向图) -* `A` [并查集](src/data-structures/disjoint-set) -* `A` [布隆过滤器](src/data-structures/bloom-filter) +- `B` [链表](src/data-structures/linked-list/README.zh-CN.md) +- `B` [双向链表](src/data-structures/doubly-linked-list/README.zh-CN.md) +- `B` [队列](src/data-structures/queue/README.zh-CN.md) +- `B` [栈](src/data-structures/stack/README.zh-CN.md) +- `B` [哈希表(散列)](src/data-structures/hash-table/README.zh-CN.md) +- `B` [堆](src/data-structures/heap/README.zh-CN.md) - 最大堆 & 最小堆 +- `B` [优先队列](src/data-structures/priority-queue/README.zh-CN.md) +- `A` [字典树](src/data-structures/trie/README.zh-CN.md) +- `A` [树](src/data-structures/tree/README.zh-CN.md) + - `A` [二叉查找树](src/data-structures/tree/binary-search-tree) + - `A` [AVL 树](src/data-structures/tree/avl-tree) + - `A` [红黑树](src/data-structures/tree/red-black-tree) + - `A` [线段树](src/data-structures/tree/segment-tree) - 使用 `最小/最大/总和` 范围查询示例 + - `A` [树状数组](src/data-structures/tree/fenwick-tree) (二叉索引树) +- `A` [图](src/data-structures/graph/README.zh-CN.md) (有向图与无向图) +- `A` [并查集](src/data-structures/disjoint-set) +- `A` [布隆过滤器](src/data-structures/bloom-filter) ## 算法 @@ -59,153 +59,154 @@ _Read this in other languages:_ ### 算法主题 -* **数学** - * `B` [位运算](src/algorithms/math/bits) - set/get/update/clear 位、乘以/除以二进制位 、变负等 - * `B` [阶乘](src/algorithms/math/factorial/README.zh-CN.md) - * `B` [斐波那契数](src/algorithms/math/fibonacci) - `经典` 和 `闭式` 版本 - * `B` [素数检测](src/algorithms/math/primality-test) (排除法) - * `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD) - * `B` [最小公倍数](src/algorithms/math/least-common-multiple) (LCM) - * `B` [素数筛](src/algorithms/math/sieve-of-eratosthenes) - 查找任意给定范围内的所有素数 - * `B` [判断 2 次方数](src/algorithms/math/is-power-of-two) - 检查数字是否为 2 的幂 (原生和按位算法) - * `B` [杨辉三角形](src/algorithms/math/pascal-triangle) - * `B` [复数](src/algorithms/math/complex-number) - 复数及其基本运算 - * `B` [弧度和角](src/algorithms/math/radian) - 弧度与角的相互转换 - * `B` [快速算次方](src/algorithms/math/fast-powering) - * `A` [整数拆分](src/algorithms/math/integer-partition) - * `A` [割圆术](src/algorithms/math/liu-hui) - 基于 N-gons 的近似 π 计算 - * `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率 -* **集合** - * `B` [笛卡尔积](src/algorithms/sets/cartesian-product) - 多集合结果 - * `A` [洗牌算法](src/algorithms/sets/fisher-yates) - 随机置换有限序列 - * `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集 - * `A` [排列](src/algorithms/sets/permutations) (有/无重复) - * `A` [组合](src/algorithms/sets/combinations) (有/无重复) - * `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS) - * `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence) - * `A` [最短公共父序列](src/algorithms/sets/shortest-common-supersequence) (SCS) - * `A` [背包问题](src/algorithms/sets/knapsack-problem) - `0/1` 和 `无边界` 问题 - * `A` [最大子数列问题](src/algorithms/sets/maximum-subarray) - `BF 算法` 和 `动态规划` - * `A` [组合求和](src/algorithms/sets/combination-sum) - 查找形成特定总和的所有组合 -* **字符串** - * `B` [汉明距离](src/algorithms/string/hamming-distance) - 符号不同的位置数 - * `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 - * `A` [Knuth–Morris–Pratt 算法](src/algorithms/string/knuth-morris-pratt) KMP 算法 - 子串搜索 (模式匹配) - * `A` [字符串快速查找](src/algorithms/string/z-algorithm) - 子串搜索 (模式匹配) - * `A` [Rabin Karp 算法](src/algorithms/string/rabin-karp) - 子串搜索 - * `A` [最长公共子串](src/algorithms/string/longest-common-substring) - * `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching) -* **搜索** - * `B` [线性搜索](src/algorithms/search/linear-search) - * `B` [跳转搜索/块搜索](src/algorithms/search/jump-search) - 搜索有序数组 - * `B` [二分查找](src/algorithms/search/binary-search) - 搜索有序数组 - * `B` [插值搜索](src/algorithms/search/interpolation-search) - 搜索均匀分布的有序数组 -* **排序** - * `B` [冒泡排序](src/algorithms/sorting/bubble-sort) - * `B` [选择排序](src/algorithms/sorting/selection-sort) - * `B` [插入排序](src/algorithms/sorting/insertion-sort) - * `B` [堆排序](src/algorithms/sorting/heap-sort) - * `B` [归并排序](src/algorithms/sorting/merge-sort) - * `B` [快速排序](src/algorithms/sorting/quick-sort) - in-place (原地) 和 non-in-place 版本 - * `B` [希尔排序](src/algorithms/sorting/shell-sort) - * `B` [计数排序](src/algorithms/sorting/counting-sort) - * `B` [基数排序](src/algorithms/sorting/radix-sort) -* **链表** +- **数学** + - `B` [位运算](src/algorithms/math/bits) - set/get/update/clear 位、乘以/除以二进制位 、变负等 + - `B` [阶乘](src/algorithms/math/factorial/README.zh-CN.md) + - `B` [斐波那契数](src/algorithms/math/fibonacci) - `经典` 和 `闭式` 版本 + - `B` [素数检测](src/algorithms/math/primality-test) (排除法) + - `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD) + - `B` [最小公倍数](src/algorithms/math/least-common-multiple) (LCM) + - `B` [素数筛](src/algorithms/math/sieve-of-eratosthenes) - 查找任意给定范围内的所有素数 + - `B` [判断 2 次方数](src/algorithms/math/is-power-of-two) - 检查数字是否为 2 的幂 (原生和按位算法) + - `B` [杨辉三角形](src/algorithms/math/pascal-triangle) + - `B` [复数](src/algorithms/math/complex-number) - 复数及其基本运算 + - `B` [弧度和角](src/algorithms/math/radian) - 弧度与角的相互转换 + - `B` [快速算次方](src/algorithms/math/fast-powering) + - `A` [整数拆分](src/algorithms/math/integer-partition) + - `A` [割圆术](src/algorithms/math/liu-hui) - 基于 N-gons 的近似 π 计算 + - `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率 +- **集合** + - `B` [笛卡尔积](src/algorithms/sets/cartesian-product) - 多集合结果 + - `A` [洗牌算法](src/algorithms/sets/fisher-yates) - 随机置换有限序列 + - `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集 + - `A` [排列](src/algorithms/sets/permutations) (有/无重复) + - `A` [组合](src/algorithms/sets/combinations) (有/无重复) + - `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS) + - `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence) + - `A` [最短公共父序列](src/algorithms/sets/shortest-common-supersequence) (SCS) + - `A` [背包问题](src/algorithms/sets/knapsack-problem) - `0/1` 和 `无边界` 问题 + - `A` [最大子数列问题](src/algorithms/sets/maximum-subarray) - `BF 算法` 和 `动态规划` + - `A` [组合求和](src/algorithms/sets/combination-sum) - 查找形成特定总和的所有组合 +- **字符串** + - `B` [汉明距离](src/algorithms/string/hamming-distance) - 符号不同的位置数 + - `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 + - `A` [Knuth–Morris–Pratt 算法](src/algorithms/string/knuth-morris-pratt) KMP 算法 - 子串搜索 (模式匹配) + - `A` [字符串快速查找](src/algorithms/string/z-algorithm) - 子串搜索 (模式匹配) + - `A` [Rabin Karp 算法](src/algorithms/string/rabin-karp) - 子串搜索 + - `A` [最长公共子串](src/algorithms/string/longest-common-substring) + - `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching) +- **搜索** + - `B` [线性搜索](src/algorithms/search/linear-search) + - `B` [跳转搜索/块搜索](src/algorithms/search/jump-search) - 搜索有序数组 + - `B` [二分查找](src/algorithms/search/binary-search) - 搜索有序数组 + - `B` [插值搜索](src/algorithms/search/interpolation-search) - 搜索均匀分布的有序数组 +- **排序** + - `B` [冒泡排序](src/algorithms/sorting/bubble-sort) + - `B` [选择排序](src/algorithms/sorting/selection-sort) + - `B` [插入排序](src/algorithms/sorting/insertion-sort) + - `B` [堆排序](src/algorithms/sorting/heap-sort) + - `B` [归并排序](src/algorithms/sorting/merge-sort) + - `B` [快速排序](src/algorithms/sorting/quick-sort) - in-place (原地) 和 non-in-place 版本 + - `B` [希尔排序](src/algorithms/sorting/shell-sort) + - `B` [计数排序](src/algorithms/sorting/counting-sort) + - `B` [基数排序](src/algorithms/sorting/radix-sort) +- **链表** - `B` [正向遍历](src/algorithms/linked-list/traversal) - `B` [反向遍历](src/algorithms/linked-list/reverse-traversal) -* **树** - * `B` [深度优先搜索](src/algorithms/tree/depth-first-search) (DFS) - * `B` [广度优先搜索](src/algorithms/tree/breadth-first-search) (BFS) -* **图** - * `B` [深度优先搜索](src/algorithms/graph/depth-first-search) (DFS) - * `B` [广度优先搜索](src/algorithms/graph/breadth-first-search) (BFS) - * `B` [克鲁斯克尔演算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST) - * `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到图中所有顶点的最短路径 - * `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到图中所有顶点的最短路径 - * `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对 之间的最短路径 - * `A` [判圈算法](src/algorithms/graph/detect-cycle) - 对于有向图和无向图 (基于 DFS 和不相交集的版本) - * `A` [普林演算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST) - * `A` [拓扑排序](src/algorithms/graph/topological-sorting) - DFS 方法 - * `A` [关节点](src/algorithms/graph/articulation-points) - Tarjan 算法 (基于 DFS) - * `A` [桥](src/algorithms/graph/bridges) - 基于 DFS 的算法 - * `A` [欧拉回径与一笔画问题](src/algorithms/graph/eulerian-path) - Fleury 的算法 - 一次访问每个边 - * `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 - * `A` [强连通分量](src/algorithms/graph/strongly-connected-components) - Kosaraju 算法 - * `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 -* **加密** - * `B` [多项式 hash](src/algorithms/cryptography/polynomial-hash) - 基于多项式的 rolling hash 函数 -* **机器学习** - * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) -7个简单的JS函数,说明机器如何实际学习(向前/向后传播) -* **未分类** - * `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower) - * `B` [旋转矩阵](src/algorithms/uncategorized/square-matrix-rotation) - 原地算法 - * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - 回溯,、动态编程 (自上而下+自下而上) 和贪婪的例子 - * `B` [独特(唯一) 路径](src/algorithms/uncategorized/unique-paths) - 回溯、动态编程和基于 Pascal 三角形的例子 - * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱捕雨水问题 (动态编程和暴力版本) - * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案) - * `A` [八皇后问题](src/algorithms/uncategorized/n-queens) - * `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour) +- **树** + - `B` [深度优先搜索](src/algorithms/tree/depth-first-search) (DFS) + - `B` [广度优先搜索](src/algorithms/tree/breadth-first-search) (BFS) +- **图** + - `B` [深度优先搜索](src/algorithms/graph/depth-first-search) (DFS) + - `B` [广度优先搜索](src/algorithms/graph/breadth-first-search) (BFS) + - `B` [克鲁斯克尔演算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST) + - `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到图中所有顶点的最短路径 + - `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到图中所有顶点的最短路径 + - `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对 之间的最短路径 + - `A` [判圈算法](src/algorithms/graph/detect-cycle) - 对于有向图和无向图 (基于 DFS 和不相交集的版本) + - `A` [普林演算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST) + - `A` [拓扑排序](src/algorithms/graph/topological-sorting) - DFS 方法 + - `A` [关节点](src/algorithms/graph/articulation-points) - Tarjan 算法 (基于 DFS) + - `A` [桥](src/algorithms/graph/bridges) - 基于 DFS 的算法 + - `A` [欧拉回径与一笔画问题](src/algorithms/graph/eulerian-path) - Fleury 的算法 - 一次访问每个边 + - `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 + - `A` [强连通分量](src/algorithms/graph/strongly-connected-components) - Kosaraju 算法 + - `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 +- **加密** + - `B` [多项式 hash](src/algorithms/cryptography/polynomial-hash) - 基于多项式的 rolling hash 函数 +- **机器学习** + - `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) -7 个简单的 JS 函数,说明机器如何实际学习(向前/向后传播) +- **未分类** + - `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower) + - `B` [旋转矩阵](src/algorithms/uncategorized/square-matrix-rotation) - 原地算法 + - `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - 回溯,、动态编程 (自上而下+自下而上) 和贪婪的例子 + - `B` [独特(唯一) 路径](src/algorithms/uncategorized/unique-paths) - 回溯、动态编程和基于 Pascal 三角形的例子 + - `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱捕雨水问题 (动态编程和暴力版本) + - `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案) + - `A` [八皇后问题](src/algorithms/uncategorized/n-queens) + - `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour) ### 算法范式 算法范式是一种通用方法,基于一类算法的设计。这是比算法更高的抽象,就像算法是比计算机程序更高的抽象。 -* **BF 算法** - `查找/搜索` 所有可能性并选择最佳解决方案 - * `B` [线性搜索](src/algorithms/search/linear-search) - * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱导雨水问题 - * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案) - * `A` [最大子数列](src/algorithms/sets/maximum-subarray) - * `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 - * `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率 -* **贪心法** - 在当前选择最佳选项,不考虑以后情况 - * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - * `A` [背包问题](src/algorithms/sets/knapsack-problem) - * `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径 - * `A` [普里姆算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST) - * `A` [克鲁斯卡尔算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST) -* **分治法** - 将问题分成较小的部分,然后解决这些部分 - * `B` [二分查找](src/algorithms/search/binary-search) - * `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower) - * `B` [杨辉三角形](src/algorithms/math/pascal-triangle) - * `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD) - * `B` [归并排序](src/algorithms/sorting/merge-sort) - * `B` [快速排序](src/algorithms/sorting/quick-sort) - * `B` [树深度优先搜索](src/algorithms/tree/depth-first-search) (DFS) - * `B` [图深度优先搜索](src/algorithms/graph/depth-first-search) (DFS) - * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - * `B` [快速算次方](src/algorithms/math/fast-powering) - * `A` [排列](src/algorithms/sets/permutations) (有/无重复) - * `A` [组合](src/algorithms/sets/combinations) (有/无重复) -* **动态规划(Dynamic programming)** - 使用以前找到的子解决方案构建解决方案 - * `B` [斐波那契数](src/algorithms/math/fibonacci) - * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - * `B` [独特路径](src/algorithms/uncategorized/unique-paths) - * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 疏导雨水问题 - * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案) - * `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 - * `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS) - * `A` [最长公共子串](src/algorithms/string/longest-common-substring) - * `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence) - * `A` [最短公共子序列](src/algorithms/sets/shortest-common-supersequence) - * `A` [0-1背包问题](src/algorithms/sets/knapsack-problem) - * `A` [整数拆分](src/algorithms/math/integer-partition) - * `A` [最大子数列](src/algorithms/sets/maximum-subarray) - * `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径 - * `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对之间的最短路径 - * `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching) -* **回溯法** - 类似于 `BF 算法` 试图产生所有可能的解决方案,但每次生成解决方案测试如果它满足所有条件,那么只有继续生成后续解决方案。否则回溯并继续寻找不同路径的解决方案。 - * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - * `B` [独特路径](src/algorithms/uncategorized/unique-paths) - * `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集 - * `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 - * `A` [八皇后问题](src/algorithms/uncategorized/n-queens) - * `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour) - * `A` [组合求和](src/algorithms/sets/combination-sum) - 从规定的总和中找出所有的组合 -* **Branch & Bound** - 记住在回溯搜索的每个阶段找到的成本最低的解决方案,并使用到目前为止找到的成本最小值作为下限。以便丢弃成本大于最小值的解决方案。通常,使用 BFS 遍历以及状态空间树的 DFS 遍历。 +- **BF 算法** - `查找/搜索` 所有可能性并选择最佳解决方案 + - `B` [线性搜索](src/algorithms/search/linear-search) + - `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱导雨水问题 + - `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案) + - `A` [最大子数列](src/algorithms/sets/maximum-subarray) + - `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 + - `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率 +- **贪心法** - 在当前选择最佳选项,不考虑以后情况 + - `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) + - `A` [背包问题](src/algorithms/sets/knapsack-problem) + - `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径 + - `A` [普里姆算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST) + - `A` [克鲁斯卡尔算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST) +- **分治法** - 将问题分成较小的部分,然后解决这些部分 + - `B` [二分查找](src/algorithms/search/binary-search) + - `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower) + - `B` [杨辉三角形](src/algorithms/math/pascal-triangle) + - `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD) + - `B` [归并排序](src/algorithms/sorting/merge-sort) + - `B` [快速排序](src/algorithms/sorting/quick-sort) + - `B` [树深度优先搜索](src/algorithms/tree/depth-first-search) (DFS) + - `B` [图深度优先搜索](src/algorithms/graph/depth-first-search) (DFS) + - `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) + - `B` [快速算次方](src/algorithms/math/fast-powering) + - `A` [排列](src/algorithms/sets/permutations) (有/无重复) + - `A` [组合](src/algorithms/sets/combinations) (有/无重复) +- **动态规划(Dynamic programming)** - 使用以前找到的子解决方案构建解决方案 + - `B` [斐波那契数](src/algorithms/math/fibonacci) + - `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) + - `B` [独特路径](src/algorithms/uncategorized/unique-paths) + - `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 疏导雨水问题 + - `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案) + - `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 + - `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS) + - `A` [最长公共子串](src/algorithms/string/longest-common-substring) + - `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence) + - `A` [最短公共子序列](src/algorithms/sets/shortest-common-supersequence) + - `A` [0-1 背包问题](src/algorithms/sets/knapsack-problem) + - `A` [整数拆分](src/algorithms/math/integer-partition) + - `A` [最大子数列](src/algorithms/sets/maximum-subarray) + - `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径 + - `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对之间的最短路径 + - `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching) +- **回溯法** - 类似于 `BF 算法` 试图产生所有可能的解决方案,但每次生成解决方案测试如果它满足所有条件,那么只有继续生成后续解决方案。否则回溯并继续寻找不同路径的解决方案。 + - `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) + - `B` [独特路径](src/algorithms/uncategorized/unique-paths) + - `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集 + - `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 + - `A` [八皇后问题](src/algorithms/uncategorized/n-queens) + - `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour) + - `A` [组合求和](src/algorithms/sets/combination-sum) - 从规定的总和中找出所有的组合 +- **Branch & Bound** - 记住在回溯搜索的每个阶段找到的成本最低的解决方案,并使用到目前为止找到的成本最小值作为下限。以便丢弃成本大于最小值的解决方案。通常,使用 BFS 遍历以及状态空间树的 DFS 遍历。 ## 如何使用本仓库 **安装依赖** + ``` npm install ``` @@ -225,6 +226,7 @@ npm test ``` **按照名称执行测试** + ``` npm test -- 'LinkedList' ``` @@ -245,53 +247,67 @@ npm test -- 'playground' [▶ YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) -### 大O符号 +### 大 O 符号 -大O符号中指定的算法的增长顺序。 +大 O 符号中指定的算法的增长顺序。  源: [Big O Cheat Sheet](http://bigocheatsheet.com/). -以下是一些最常用的 大O标记法 列表以及它们与不同大小输入数据的性能比较。 +以下是一些最常用的 大 O 标记法 列表以及它们与不同大小输入数据的性能比较。 -| 大O标记法 | 计算10个元素 | 计算100个元素 | 计算1000个元素 | -| -------------- | ---------------------------- | ----------------------------- | ------------------------------- | -| **O(1)** | 1 | 1 | 1 | -| **O(log N)** | 3 | 6 | 9 | -| **O(N)** | 10 | 100 | 1000 | -| **O(N log N)** | 30 | 600 | 9000 | -| **O(N^2)** | 100 | 10000 | 1000000 | -| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | -| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | +| 大 O 标记法 | 计算 10 个元素 | 计算 100 个元素 | 计算 1000 个元素 | +| -------------- | -------------- | --------------- | ---------------- | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | ### 数据结构操作的复杂性 -| 数据结构 | 连接 | 查找 | 插入 | 删除 | 备注 | -| -------------- | :----: | :----: | :----: | :----: | ---- | -| **数组** | 1 | n | n | n | | -| **栈** | n | n | 1 | 1 | | -| **队列** | n | n | 1 | 1 | | -| **链表** | n | n | 1 | 1 | | +| 数据结构 | 连接 | 查找 | 插入 | 删除 | 备注 | +| -------------- | :----: | :----: | :----: | :----: | ------------------------------------ | +| **数组** | 1 | n | n | n | | +| **栈** | n | n | 1 | 1 | | +| **队列** | n | n | 1 | 1 | | +| **链表** | n | n | 1 | 1 | | | **哈希表** | - | n | n | n | 在完全哈希函数情况下,复杂度是 O(1) | -| **二分查找树** | n | n | n | n | 在平衡树情况下,复杂度是 O(log(n)) | -| **B 树** | log(n) | log(n) | log(n) | log(n) | | -| **红黑树** | log(n) | log(n) | log(n) | log(n) | | -| **AVL 树** | log(n) | log(n) | log(n) | log(n) | | -| **布隆过滤器** | - | 1 | 1 | - | 存在一定概率的判断错误(误判成存在) | +| **二分查找树** | n | n | n | n | 在平衡树情况下,复杂度是 O(log(n)) | +| **B 树** | log(n) | log(n) | log(n) | log(n) | | +| **红黑树** | log(n) | log(n) | log(n) | log(n) | | +| **AVL 树** | log(n) | log(n) | log(n) | log(n) | | +| **布隆过滤器** | - | 1 | 1 | - | 存在一定概率的判断错误(误判成存在) | ### 数组排序算法的复杂性 -| 名称 | 最优 | 平均 | 最坏 | 内存 | 稳定 | 备注 | -| --------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: | --------------------- | -| **冒泡排序** | n | n^2 | n^2 | 1 | Yes | | -| **插入排序** | n | n^2 | n^2 | 1 | Yes | | -| **选择排序** | n^2 | n^2 | n^2 | 1 | No | | -| **堆排序** | n log(n) | n log(n) | n log(n) | 1 | No | | -| **归并排序** | n log(n) | n log(n) | n log(n) | n | Yes | | -| **快速排序** | n log(n) | n log(n) | n^2 | log(n) | No | 在 in-place 版本下,内存复杂度通常是 O(log(n)) | -| **希尔排序** | n log(n) | 取决于差距序列 | n (log(n))^2 | 1 | No | | -| **计数排序** | n + r | n + r | n + r | n + r | Yes | r - 数组里最大的数 | -| **基数排序** | n * k | n * k | n * k | n + k | Yes | k - 最长 key 的升序 | +| 名称 | 最优 | 平均 | 最坏 | 内存 | 稳定 | 备注 | +| ------------ | :------: | :------------: | :----------: | :----: | :--: | ---------------------------------------------- | +| **冒泡排序** | n | n^2 | n^2 | 1 | Yes | | +| **插入排序** | n | n^2 | n^2 | 1 | Yes | | +| **选择排序** | n^2 | n^2 | n^2 | 1 | No | | +| **堆排序** | n log(n) | n log(n) | n log(n) | 1 | No | | +| **归并排序** | n log(n) | n log(n) | n log(n) | n | Yes | | +| **快速排序** | n log(n) | n log(n) | n^2 | log(n) | No | 在 in-place 版本下,内存复杂度通常是 O(log(n)) | +| **希尔排序** | n log(n) | 取决于差距序列 | n (log(n))^2 | 1 | No | | +| **计数排序** | n + r | n + r | n + r | n + r | Yes | r - 数组里最大的数 | +| **基数排序** | n \* k | n \* k | n \* k | n + k | Yes | k - 最长 key 的升序 | > ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) + +## 扩展学习 + +- [TypeScript 版本](https://github.com/loiane/javascript-datastructures-algorithms) +- [算法可视化](https://visualgo.net/zh) + +参考资料 + +- https://github.com/loiane/javascript-datastructures-algorithms +- https://visualgo.net/zh +- https://coolshell.cn/articles/4671.html + - https://www.cs.usfca.edu/~galles/visualization/Algorithms.html + - https://www.cs.usfca.edu/~galles/visualization/source.html + - [常用数据结构对比及其应用场景](https://www.jianshu.com/p/ec17d738327f) diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000000..a24e7b4116 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,90 @@ +# 算法练习 + +- 阶乘函数 [factorial] +- 斐波那契数列 [fibonacci] +- 全局唯一标识符 + - [uuid] + - [guid] + - Twitter的雪花算法 [snowflake] +- LZ系列压缩算法 + - LZ系列压缩算法均为LZ77与LZ78的变种,在此基础上做了优化。 + - LZ77:LZSS、LZR、LZB、LZH; + - LZ78:LZW、LZC、LZT、LZMW、LZJ、LZFG。 + - 其中,LZSS与LZW为这两大阵容里名气最响亮的算法。LZSS是由Storer与Szymanski [2]改进了LZ77:增加最小匹配长度的限制,当最长匹配的长度小于该限制时,则不压缩输出,但仍然滑动窗口右移一个字符。Google开源的Snappy压缩算法库大体遵循LZSS的编码方案,在其基础上做了一些工程上的优化。 +- LRU +- 判断回文数 +- 最长回文子串 https://www.cnblogs.com/en-heng/p/3973679.html +- 去掉重复值(数组) +- 找出字符串中出现次数最多的字母 +- 求最大值、最小值 +- 验证是否为数组 + +迷宫生成算法 https://zhuanlan.zhihu.com/p/47395955 +https://bost.ocks.org/mike/algorithms/#maze-generation +https://github.com/luobotang/maze +https://bost.ocks.org/mike/ + +Java程序员3面小米,被俩算法题难倒,微软员工6分钟解决,真丢脸 +https://zhuanlan.zhihu.com/p/38850888 + +各种算法题等 +https://blog.csdn.net/v_JULY_v + + +为什么算法这么难? https://zhuanlan.zhihu.com/p/25101438 + +FreeCodeCamp 高级算法题 - 字符串排列 https://zhuanlan.zhihu.com/p/30567628 +https://zhuanlan.zhihu.com/p/27659059 + +Node.js大众点评爬虫 https://www.cnblogs.com/en-heng/p/5895207.html + +- lz77 算法 + - https://www.jb51.net/article/23024.htm + - https://www.jb51.net/article/120912.htm + +- 随机算法 random + - uuid + - 随机洗牌 knuth-shuffle + - http://caibaojian.com/js-random-array.html + - https://www.h5jun.com/post/array-shuffle.html + - http://caibaojian.com/get-random-element.html + - 5分钟现场撸代码——谈总结会抽奖程序 https://www.h5jun.com/post/luckey-draw-in-5-minutes.html + +- Twitter的雪花算法 snowflake + +重学前端 https://www.w3cplus.com/relearn-the-front-end-techniques.html + +排序算法 + +第三届360前端星计划在线作业题 +https://www.h5jun.com/post/75team-star-handlock.html + +用65行代码实现JavaScript动画序列播放 +https://www.h5jun.com/post/sixty-lines-of-code-animation.html + +为什么 [ ] 是 false 而 !![ ] 是 true +https://www.h5jun.com/post/why-false-why-true.html + +https://www.cnblogs.com/en-heng/category/582209.html +【十大经典数据挖掘算法】SVM系列 https://www.cnblogs.com/en-heng/p/5965438.html + +别人家的面试题:不可变数组快速范围求和 https://75team.com/post/range-sum-query-immutable.html +别人家的面试题:自然数拆分求最大乘积 https://75team.com/post/integer-break.html + +别人家的面试题:统计“1”的个数(续) https://75team.com/post/count_bits.html + +https://www.h5jun.com/post/html5-element-flowchart.html +HTML5 元素选择流程图 + +https://www.h5jun.com/post/multiply7.html 别人家的面试题:不用加减乘除,求整数的7倍 + +C4.5 +K-Means +SVM +Apriori +EM +PageRank +AdaBoost +kNN +Naïve Bayes +CART diff --git a/examples/factorial/README.md b/examples/factorial/README.md new file mode 100644 index 0000000000..13bbfea9da --- /dev/null +++ b/examples/factorial/README.md @@ -0,0 +1,9 @@ +# 阶乘函数 Factorial + +描述:一个正整数的阶乘是所有小于及等于该数的正整数的积,并且有`0`的阶乘为`1`。自然数`n`的阶乘写作`n!`。 + +阶乘函数是[递归(Haskell)函数](https://zh.wikibooks.org/zh/Haskell/%E9%80%92%E5%BD%92)典型示例 + +参考资料: + +- https://www.w3cplus.com/javascript/factorial-function-in-javascript.html diff --git a/examples/fibonacci/README.md b/examples/fibonacci/README.md new file mode 100644 index 0000000000..694d7816a8 --- /dev/null +++ b/examples/fibonacci/README.md @@ -0,0 +1,10 @@ +# 斐波那契数列 fibonacci + +
+ +使用 JavaScript 尽可能快地来计算斐波那契数列。 + +from https://github.com/jskit/kit-fibonacci diff --git a/examples/fibonacci/__test__/fastfib.spec.js b/examples/fibonacci/__test__/fastfib.spec.js new file mode 100644 index 0000000000..e1ff4c99bc --- /dev/null +++ b/examples/fibonacci/__test__/fastfib.spec.js @@ -0,0 +1,18 @@ +const assert = require('assert'); +const fastfib = require('../lib/index'); + +assert.equal(fastfib(0), 0); +assert.equal(fastfib(1), 1); +assert.equal(fastfib(2), 1); +assert.equal(fastfib(3), 2); +assert.equal(fastfib(4), 3); +assert.equal(fastfib(5), 5); +assert.equal(fastfib(6), 8); +assert.equal(fastfib(7), 13); +assert.equal(fastfib(8), 21); +assert.equal(fastfib(9), 34); +assert.equal(fastfib(10), 55); +assert.equal(fastfib(11), 89); +assert.equal(fastfib(12), 144); + +console.log('Test passed'); diff --git a/examples/fibonacci/benchmark/index.js b/examples/fibonacci/benchmark/index.js new file mode 100644 index 0000000000..11d483900d --- /dev/null +++ b/examples/fibonacci/benchmark/index.js @@ -0,0 +1,30 @@ + +// https://www.npmjs.com/package/benchmark + +const assert = require('assert'); +const suite = new (require('benchmark')).Suite; +const recurse = require('../lib/recurse'); +const tail = require('../lib/tail'); +const iter = require('../lib/iter'); + +/* eslint new-parens: 0 */ +// const suite = new Suite + +/* eslint func-names: 0 */ +suite + .add('recurse', () => { recurse(20); }) + .add('tail', () => { tail(20); }) + .add('iter', () => { iter(20); }) + .on('complete', function () { + console.log('result: '); + // console.log(this) + this.forEach((result) => { + console.log(result.name, result.count, result.times.elapsed); + }); + assert.equal( + this.filter('fastest').map('name'), + 'iter', + 'expect iter to be the fastest', + ); + }) + .run(); diff --git a/examples/fibonacci/package.json b/examples/fibonacci/package.json new file mode 100644 index 0000000000..9a9de2393d --- /dev/null +++ b/examples/fibonacci/package.json @@ -0,0 +1,37 @@ +{ + "name": "kit-fibonacci", + "version": "1.0.2", + "description": "fastfib 使用 JavaScript 尽可能快地来计算斐波那契数列。", + "main": "lib/index.js", + "scripts": { + "prepublishOnly": "npm run lib", + "lib": "babel src -d lib", + "test": "node test/fastfib.spec.js && node benchmark" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/jskit/kit-fibonacci.git" + }, + "keywords": [ + "fibonacci", + "fastfib", + "kitjs" + ], + "author": "cloudyan <1395093509@qq.com>", + "license": "MIT", + "bugs": { + "url": "https://github.com/jskit/kit-fibonacci/issues" + }, + "homepage": "https://github.com/jskit/kit-fibonacci#readme", + "dependencies": {}, + "devDependencies": { + "babel-core": "^6.26.0", + "babel-eslint": "^8.0.3", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-plugin-transform-runtime": "^6.23.0", + "babel-preset-env": "^1.6.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-stage-2": "^6.24.1", + "benchmark": "^2.1.4" + } +} diff --git a/examples/fibonacci/src/index.js b/examples/fibonacci/src/index.js new file mode 100644 index 0000000000..48aff2e056 --- /dev/null +++ b/examples/fibonacci/src/index.js @@ -0,0 +1,5 @@ +// import recurse from './recurse' +// import tail from './tail' +import iter from './iter'; + +export default iter; diff --git a/examples/fibonacci/src/iter.js b/examples/fibonacci/src/iter.js new file mode 100644 index 0000000000..285526fb6a --- /dev/null +++ b/examples/fibonacci/src/iter.js @@ -0,0 +1,20 @@ + +/** + * 迭代方式来实现斐波那契数列 + * + * @param {number} n + * @returns + */ +function iter(n) { + let current = 0; + let next = 1; + /* eslint no-plusplus: 0 */ + for (let i = 0; i < n; i++) { + const swap = current; + current = next; + next = swap + next; + } + return current; +} + +export default iter; diff --git a/examples/fibonacci/src/recurse.js b/examples/fibonacci/src/recurse.js new file mode 100644 index 0000000000..59cb915353 --- /dev/null +++ b/examples/fibonacci/src/recurse.js @@ -0,0 +1,15 @@ + + +/** + * 递归方法实现斐波那契数列 + * + * @param {number} n + * @returns + */ +function recurse(n) { + if (n === 0) return 0; + if (n === 1) return 1; + return recurse(n - 1) + recurse(n - 2); +} + +export default recurse; diff --git a/examples/fibonacci/src/tail.js b/examples/fibonacci/src/tail.js new file mode 100644 index 0000000000..27dc02c051 --- /dev/null +++ b/examples/fibonacci/src/tail.js @@ -0,0 +1,25 @@ + +/** + * 尾递归优化 + * + * @param {number} n + * @param {number} current + * @param {number} next + * @returns + */ +function fib(n, current, next) { + if (n === 0) return current; + return fib(n - 1, next, current + next); +} + +/** + * 尾递归优化实现斐波那契数列 + * + * @param {number} n + * @returns + */ +function tail(n) { + return fib(n, 0, 1); +} + +export default tail; diff --git a/examples/fibonacci/ts/index.ts b/examples/fibonacci/ts/index.ts new file mode 100644 index 0000000000..48aff2e056 --- /dev/null +++ b/examples/fibonacci/ts/index.ts @@ -0,0 +1,5 @@ +// import recurse from './recurse' +// import tail from './tail' +import iter from './iter'; + +export default iter; diff --git a/examples/fibonacci/ts/iter.ts b/examples/fibonacci/ts/iter.ts new file mode 100644 index 0000000000..f7e547706e --- /dev/null +++ b/examples/fibonacci/ts/iter.ts @@ -0,0 +1,24 @@ + +/** + * 迭代方式来实现斐波那契数列 + * + * @param {number} n + * @returns {number} + */ +function iter(n: number): number { + let current = 0; + let next = 1; + /* eslint no-plusplus: 0 */ + for (let i = 0; i < n; i++) { + const swap = current; + current = next; + next = swap + next; + } + return current; +} + +// test +console.log(iter(5)) +console.log(iter(15)) + +export default iter; diff --git a/examples/fibonacci/ts/recurse.ts b/examples/fibonacci/ts/recurse.ts new file mode 100644 index 0000000000..1684d1b23f --- /dev/null +++ b/examples/fibonacci/ts/recurse.ts @@ -0,0 +1,14 @@ + +/** + * 递归方法实现斐波那契数列 + * + * @param {number} n + * @returns {*} + */ +function recurse(n: number): any { + if (n === 0) return 0; + if (n === 1) return 1; + return recurse(n - 1) + recurse(n - 2); +} + +export default recurse; diff --git a/examples/fibonacci/ts/tail.ts b/examples/fibonacci/ts/tail.ts new file mode 100644 index 0000000000..c1cfd7bfec --- /dev/null +++ b/examples/fibonacci/ts/tail.ts @@ -0,0 +1,25 @@ + +/** + * 尾递归优化 + * + * @param {number} n + * @param {number} current + * @param {number} next + * @returns {*} + */ +function fib(n: number, current: number, next: number): any { + if (n === 0) return current; + return fib(n - 1, next, current + next); +} + +/** + * 尾递归优化实现斐波那契数列 + * + * @param {number} n + * @returns + */ +function tail(n: number) { + return fib(n, 0, 1); +} + +export default tail; diff --git a/examples/fibonacci/ts/tempCodeRunnerFile.ts b/examples/fibonacci/ts/tempCodeRunnerFile.ts new file mode 100644 index 0000000000..45c3b5bfcd --- /dev/null +++ b/examples/fibonacci/ts/tempCodeRunnerFile.ts @@ -0,0 +1,22 @@ + +/** + * 迭代方式来实现斐波那契数列 + * + * @param {number} n + * @returns {number} + */ +function iter(n: number): number { + let current = 0; + let next = 1; + /* eslint no-plusplus: 0 */ + for (let i = 0; i < n; i++) { + const swap = current; + current = next; + next = swap + next; + } + return current; +} + +// test +console.log(iter(5)) +console.log(iter(15)) \ No newline at end of file diff --git a/examples/hash/README.md b/examples/hash/README.md new file mode 100644 index 0000000000..ee2e8be1cb --- /dev/null +++ b/examples/hash/README.md @@ -0,0 +1,37 @@ +# HASH 算法 + +常用 HASH 函数 + +- 直接取余法:f(x) = x mod maxM; maxM一般是不太接近 2^t 的一个质数。 +- 乘法取整法:f(x) = trunc((x/maxX)*maxlongit) mod maxM,主要用于实数。 +- 平方取中法:f(x) = (x*x div 1000 ) mod 1000000); 平方后取中间的,每位包含信息比较多。 + +散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位。 + +常用hash算法 + +- MD5 + - MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年设计的,MD 是 Message Digest(消息摘要) 的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于 32位操作数的位操作来实现的。 + - MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。 +- SHA 家族 + - SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于2^64的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。 + +HASH 主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值. 也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系。Hash算法在信息安全方面的应用主要体现在以下的3个方面: + +- 文件校验 + - 我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。 + - MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。 +- 数字签名 + - Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。 +- 鉴权协议 + - 鉴权协议又被称作"挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。 + +参考资料: + +- [Hash(散列函数)](https://baike.baidu.com/item/Hash/390310) +- [MD5](https://baike.baidu.com/item/MD5) +- [SHA家族](https://baike.baidu.com/item/SHA%E5%AE%B6%E6%97%8F/9849595) +- [npm: md5](https://www.npmjs.com/package/md5) +- [常见hash算法的原理](http://www.cnblogs.com/zhoug2020/p/6984191.html) +- [转 从头到尾彻底解析Hash表算法](https://www.cnblogs.com/dancheblog/p/3512284.html) +- [Hash 函数的常用算法和应用领域](http://www.cnblogs.com/qianxun/archive/2011/07/03/2096773.html) diff --git a/examples/hash/src/md5.js b/examples/hash/src/md5.js new file mode 100644 index 0000000000..de77dac700 --- /dev/null +++ b/examples/hash/src/md5.js @@ -0,0 +1,8 @@ + +// https://github.com/pvorb/node-md5 +// import md5 from 'md5'; + +// message -- `String`, `Buffer`, `Array` or `Uint8Array` +// returns `String` + +// md5(message) diff --git a/examples/lz77/README.md b/examples/lz77/README.md new file mode 100644 index 0000000000..e1caaca1cd --- /dev/null +++ b/examples/lz77/README.md @@ -0,0 +1,21 @@ +# 数据压缩 lz77 算法 + +原理及实现 + +LZ77算法是采用字典做数据压缩的算法,由以色列的两位大神Jacob Ziv与Abraham Lempel在1977年发表的论文《A Universal Algorithm for Sequential Data Compression》中提出。 + +基于统计的数据压缩编码,比如Huffman编码,需要得到先验知识——信源的字符频率,然后进行压缩。但是在大多数情况下,这种先验知识是很难预先获得。因此,设计一种更为通用的数据压缩编码显得尤为重要。LZ77数据压缩算法应运而生,其核心思想:利用数据的**重复结构信息**来进行数据压缩。 + +如何描述重复结构信息,LZ77算法给出了更为确切的数学解释。首先,定义字符串S的长度为N,字符串S的子串Si,j, 1≤i,j≤N。对于前缀子串S1,j,记Lji为首字符Si的子串与首字符Sj+1的子串最大匹配的长度,即: + +``` +L_i^j = \max \{ l | S_{i,i+l-1} = S_{j+1,j+l} \} \quad \text{subject to} \quad l \le N-j +``` + +我们称字符串Sj+1,j+l匹配了字符串Si,i+l−1,且匹配长度为l。如图所示,存在两类情况: + +参考资料: + +- http://www.cnblogs.com/en-heng/p/4992916.html +- https://www.jb51.net/article/23024.htm +- https://www.jb51.net/article/120912.htm diff --git a/examples/lz78/README.md b/examples/lz78/README.md new file mode 100644 index 0000000000..0ab61d6fd0 --- /dev/null +++ b/examples/lz78/README.md @@ -0,0 +1,7 @@ +# 数据压缩 LZ78算法原理及实现 + +在提出基于滑动窗口的LZ77算法后,两位大神Jacob Ziv与Abraham Lempel于1978年在发表的论文 [1]中提出了LZ78算法;与LZ77算法不同的是LZ78算法使用动态树状词典维护历史字符串。 + +参考资料: + +- http://www.cnblogs.com/en-heng/p/6283282.html diff --git a/examples/uuid/README.md b/examples/uuid/README.md new file mode 100644 index 0000000000..972b78b936 --- /dev/null +++ b/examples/uuid/README.md @@ -0,0 +1,36 @@ +# UUID + +UUID 就是 Universal Unique IDentifier 的缩写,它是一个128位,16字节的值,并确保在时间和空间上唯一。 +它是把硬件地址、时间以及随机数结合在一起,它保证对在同一时空中的所有机器都是唯一的。 + +通常平台会提供生成UUID的API。UUID按照开放软件基金会 (OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID (Globals Unique Identifiers)。 + +GUID(Globals Unique Identifiers 全局统一标识符)是微软对UUID这个标准的实现。是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成GUID的API。生成算法很有意思,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。GUID的唯一缺陷在于生成的结果串会比较大。 + +一个GUID为一个128位的整数(16字节),在使用唯一标识符的情况下,你可以在所有计算机和网络之间使用这一整数。GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的字。例如:337c7f2b-7a34-4f50-9141-bab9e6478cc8 即为有效的 GUID 值。 + +世界上的任何两台计算机都不会生成重复的 GUID 值。GUID 主要用于在拥有多个节点、多台计算机的网络或系统中,分配必须具有唯一性的标识符。在 Windows 平台上,GUID 应用非常广泛:注册表、类及接口标识、数据库、甚至自动生成的机器名、目录名等。一个GUID可以在后台数据库中操作一个主键。 + +## 适用于分布式唯一标识码的生成算法有哪些? + +- 利用数据库生成 +- 利用Redis/MongoDB/zookeeper生成 +- UUID + - UUID有基于MAC地址的,加上时间和时钟序列的,也有基于伪随机数的,基于加密哈希的。 +- Twitter的snowflake算法 + - Twitter开源,基于zk,41位时间戳(毫秒数)+10位机器的ID+12位毫秒内的流水号+1位符号位(永远是0)。 + - 优点:性能不错,单机内递增。 + - 缺点:依赖zk;依赖于机器时钟,分布式环境内可能会不是全局递增。 +- 百度 UidGenerator + - UidGenerator是百度开源的分布式ID生成器,基于于snowflake算法的实现,看起来感觉还行。不过,国内开源的项目维护性真是担忧。 +- 美团 Leaf + - Leaf 是美团开源的分布式ID生成器,能保证全局唯一性、趋势递增、单调递增、信息安全,里面也提到了几种分布式方案的对比,但也需要依赖关系数据库、Zookeeper等中间件。 + +参考资料: + +- https://blog.csdn.net/forlong401/article/details/7580147 +- https://blog.csdn.net/yuanlianming663/article/details/1842267 +- https://www.cnblogs.com/pangguoming/p/7090906.html +- http://www.cnblogs.com/snandy/p/3261754.html +- https://m.zjurl.cn/answer/6640244087003808014/?iid=59688834959 +- https://tech.meituan.com/2017/04/21/mt-leaf.html diff --git a/examples/uuid/src/guid.js b/examples/uuid/src/guid.js new file mode 100644 index 0000000000..1569772c02 --- /dev/null +++ b/examples/uuid/src/guid.js @@ -0,0 +1,91 @@ +/*! +Math.uuid.js (v1.4) +http://www.broofa.com +mailto:robert@broofa.com + +Copyright (c) 2010 Robert Kieffer +Dual licensed under the MIT and GPL licenses. +*/ + +/* + * Generate a random uuid. + * + * USAGE: Math.uuid(length, radix) + * length - the desired number of characters + * radix - the number of allowable values for each character. + * + * EXAMPLES: + * // No arguments - returns RFC4122, version 4 ID + * >>> Math.uuid() + * "92329D39-6F5C-4520-ABFC-AAB64544E172" + * + * // One argument - returns ID of the specified length + * >>> Math.uuid(15) // 15 character ID (default base=62) + * "VcydxgltxrVZSTV" + * + * // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62) + * >>> Math.uuid(8, 2) // 8 character ID (base=2) + * "01001010" + * >>> Math.uuid(8, 10) // 8 character ID (base=10) + * "47473046" + * >>> Math.uuid(8, 16) // 8 character ID (base=16) + * "098F4D35" + */ + +// Private array of chars to use +var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + +Math.uuid = function (len, radix) { + var chars = CHARS, uuid = [], i; + radix = radix || chars.length; + + if (len) { + // Compact form + for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix]; + } else { + // rfc4122, version 4 form + var r; + + // rfc4122 requires these characters + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + // Fill in random data. At i==19 set the high bits of clock sequence as + // per rfc4122, sec. 4.1.5 + for (i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | Math.random()*16; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + } + + return uuid.join(''); +}; + +// A more performant, but slightly bulkier, RFC4122v4 solution. We boost performance +// by minimizing calls to random() +Math.uuidFast = function() { + var chars = CHARS, uuid = new Array(36), rnd=0, r; + for (var i = 0; i < 36; i++) { + if (i==8 || i==13 || i==18 || i==23) { + uuid[i] = '-'; + } else if (i==14) { + uuid[i] = '4'; + } else { + if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + return uuid.join(''); +}; + +// A more compact, but less performant, RFC4122v4 solution: +Math.uuidCompact = function() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); +}; diff --git a/examples/uuid/src/uuid.js b/examples/uuid/src/uuid.js new file mode 100644 index 0000000000..bb09a144a1 --- /dev/null +++ b/examples/uuid/src/uuid.js @@ -0,0 +1,66 @@ +function uuid() { + var s = []; + var hexDigits = "0123456789abcdef"; + for (var i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 + s[8] = s[13] = s[18] = s[23] = "-"; + + var uuid = s.join(""); + return uuid; +} + + +function guid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); +} + + +function guid() { + function S4() { + return (((1+Math.random())*0x10000)|0).toString(16).substring(1); + } + return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); +} + +function uuid(len, radix) { + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + var uuid = [], i; + radix = radix || chars.length; + + if (len) { + // Compact form + for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix]; + } else { + // rfc4122, version 4 form + var r; + + // rfc4122 requires these characters + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + // Fill in random data. At i==19 set the high bits of clock sequence as + // per rfc4122, sec. 4.1.5 + for (i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | Math.random()*16; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + } + } + } + + return uuid.join(''); +} + + +// 8 character ID (base=2) +uuid(8, 2) // "01001010" +// 8 character ID (base=10) +uuid(8, 10) // "47473046" +// 8 character ID (base=16) +uuid(8, 16) // "098F4D35" diff --git a/jest.config.js b/jest.config.js index 78568a1e94..fefe565590 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,7 +13,13 @@ module.exports = { coverageDirectory: './coverage/', // If the test path matches any of the patterns, it will be skipped. - testPathIgnorePatterns: ['