@gkucmierz/utils 1.32.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.mjs +21 -1
- package/package.json +1 -1
- package/src/Trie.mjs +64 -54
- package/src/array-histogram.mjs +17 -0
- package/src/combinations.mjs +41 -0
- package/src/gray-code.mjs +28 -0
- package/src/heap.mjs +69 -58
- package/src/n-choose-k.mjs +31 -0
- package/src/permutations.mjs +34 -0
package/main.mjs
CHANGED
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
Trie
|
|
7
7
|
} from './src/Trie.mjs'
|
|
8
|
+
import {
|
|
9
|
+
arrayHistogram
|
|
10
|
+
} from './src/array-histogram.mjs'
|
|
8
11
|
import {
|
|
9
12
|
fromBase64, fromBase64Url, toBase64, toBase64Url
|
|
10
13
|
} from './src/base64.mjs'
|
|
@@ -14,6 +17,9 @@ import {
|
|
|
14
17
|
import {
|
|
15
18
|
binarySearchArr, binarySearchGE, binarySearchLE, binarySearchRangeIncl
|
|
16
19
|
} from './src/binary-search.mjs'
|
|
20
|
+
import {
|
|
21
|
+
combinations, combinationsIterator
|
|
22
|
+
} from './src/combinations.mjs'
|
|
17
23
|
import {
|
|
18
24
|
consumeIteratorNonBlocking
|
|
19
25
|
} from './src/consume-iterator.mjs'
|
|
@@ -38,6 +44,9 @@ import {
|
|
|
38
44
|
import {
|
|
39
45
|
gpn, gpnBI
|
|
40
46
|
} from './src/gpn.mjs'
|
|
47
|
+
import {
|
|
48
|
+
bin2gray, gray2bin
|
|
49
|
+
} from './src/gray-code.mjs'
|
|
41
50
|
import {
|
|
42
51
|
Heap
|
|
43
52
|
} from './src/heap.mjs'
|
|
@@ -62,6 +71,9 @@ import {
|
|
|
62
71
|
import {
|
|
63
72
|
mod, modBI
|
|
64
73
|
} from './src/mod.mjs'
|
|
74
|
+
import {
|
|
75
|
+
nChooseK
|
|
76
|
+
} from './src/n-choose-k.mjs'
|
|
65
77
|
import {
|
|
66
78
|
naturalSearch
|
|
67
79
|
} from './src/natural-search.mjs'
|
|
@@ -71,6 +83,9 @@ import {
|
|
|
71
83
|
import {
|
|
72
84
|
particleSwarmOptimization
|
|
73
85
|
} from './src/particle-swarm.mjs'
|
|
86
|
+
import {
|
|
87
|
+
permutations, permutationsIterator
|
|
88
|
+
} from './src/permutations.mjs'
|
|
74
89
|
import {
|
|
75
90
|
phi, phiBI
|
|
76
91
|
} from './src/phi.mjs'
|
|
@@ -92,9 +107,11 @@ import {
|
|
|
92
107
|
|
|
93
108
|
export * from './src/SetCnt.mjs';
|
|
94
109
|
export * from './src/Trie.mjs';
|
|
110
|
+
export * from './src/array-histogram.mjs';
|
|
95
111
|
export * from './src/base64.mjs';
|
|
96
112
|
export * from './src/bijective-numeration.mjs';
|
|
97
113
|
export * from './src/binary-search.mjs';
|
|
114
|
+
export * from './src/combinations.mjs';
|
|
98
115
|
export * from './src/consume-iterator.mjs';
|
|
99
116
|
export * from './src/copy-case.mjs';
|
|
100
117
|
export * from './src/egcd.mjs';
|
|
@@ -103,6 +120,7 @@ export * from './src/format-big-number.mjs';
|
|
|
103
120
|
export * from './src/gcd.mjs';
|
|
104
121
|
export * from './src/get-type.mjs';
|
|
105
122
|
export * from './src/gpn.mjs';
|
|
123
|
+
export * from './src/gray-code.mjs';
|
|
106
124
|
export * from './src/heap.mjs';
|
|
107
125
|
export * from './src/herons-formula.mjs';
|
|
108
126
|
export * from './src/lcm.mjs';
|
|
@@ -111,9 +129,11 @@ export * from './src/math3d.mjs';
|
|
|
111
129
|
export * from './src/matrix.mjs';
|
|
112
130
|
export * from './src/memoize.mjs';
|
|
113
131
|
export * from './src/mod.mjs';
|
|
132
|
+
export * from './src/n-choose-k.mjs';
|
|
114
133
|
export * from './src/natural-search.mjs';
|
|
115
134
|
export * from './src/nelder-mead.mjs';
|
|
116
135
|
export * from './src/particle-swarm.mjs';
|
|
136
|
+
export * from './src/permutations.mjs';
|
|
117
137
|
export * from './src/phi.mjs';
|
|
118
138
|
export * from './src/pow-mod.mjs';
|
|
119
139
|
export * from './src/range-array.mjs';
|
|
@@ -122,5 +142,5 @@ export * from './src/square-root.mjs';
|
|
|
122
142
|
export * from './src/tonelli-shanks.mjs';
|
|
123
143
|
|
|
124
144
|
export default [
|
|
125
|
-
SetCnt, Trie, fromBase64, fromBase64Url, toBase64, toBase64Url, bijective2num, bijective2numBI, num2bijective, num2bijectiveBI, binarySearchArr, binarySearchGE, binarySearchLE, binarySearchRangeIncl, consumeIteratorNonBlocking, copyCase, egcd, factors, factorsBI, formatBigNumber, formatBigNumberBI, wrapFn, gcd, gcdBI, getType, gpn, gpnBI, Heap, heronsFormula, heronsFormulaBI, lcm, lcmBI, ListNode, axisAngleToMatrix4, crossProduct, dotProduct, getRotationMatrixFromVectors, multiplyMatrix4, normalize, projectToTrackball, matrixAsArray, memoize, mod, modBI, naturalSearch, nelderMead, particleSwarmOptimization, phi, phiBI, powMod, powModBI, array2range, range2array, simulatedAnnealing, squareRoot, squareRootBI, tonelliShanksBI
|
|
145
|
+
SetCnt, Trie, arrayHistogram, fromBase64, fromBase64Url, toBase64, toBase64Url, bijective2num, bijective2numBI, num2bijective, num2bijectiveBI, binarySearchArr, binarySearchGE, binarySearchLE, binarySearchRangeIncl, combinations, combinationsIterator, consumeIteratorNonBlocking, copyCase, egcd, factors, factorsBI, formatBigNumber, formatBigNumberBI, wrapFn, gcd, gcdBI, getType, gpn, gpnBI, bin2gray, gray2bin, Heap, heronsFormula, heronsFormulaBI, lcm, lcmBI, ListNode, axisAngleToMatrix4, crossProduct, dotProduct, getRotationMatrixFromVectors, multiplyMatrix4, normalize, projectToTrackball, matrixAsArray, memoize, mod, modBI, nChooseK, naturalSearch, nelderMead, particleSwarmOptimization, permutations, permutationsIterator, phi, phiBI, powMod, powModBI, array2range, range2array, simulatedAnnealing, squareRoot, squareRootBI, tonelliShanksBI
|
|
126
146
|
];
|
package/package.json
CHANGED
package/src/Trie.mjs
CHANGED
|
@@ -1,111 +1,121 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
* Creates a Trie (prefix tree) data structure.
|
|
4
|
-
*
|
|
5
|
-
* @param {boolean} [strict=true] - If true, removing a word cleans up unused nodes.
|
|
6
|
-
* If false, removal is faster but may leave unused nodes.
|
|
7
|
-
* @returns {object} The Trie instance with methods.
|
|
3
|
+
* Implemented as a proper ES6 Class to fix prototyping documentation and encapsulate nodes.
|
|
8
4
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
export class Trie {
|
|
6
|
+
static #HAS = 0;
|
|
7
|
+
static #MAP = 1;
|
|
8
|
+
|
|
9
|
+
#data = [false, new Map()];
|
|
10
|
+
#strict;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Initializes the Trie class object.
|
|
14
|
+
* @param {string[]} [words=[]] - Initial words to add to the Trie.
|
|
15
|
+
* @param {boolean} [strict=true] - If true, removing a word cleans up unused nodes.
|
|
16
|
+
* If false, removal is faster but may leave unused nodes.
|
|
17
|
+
*/
|
|
18
|
+
constructor(words = [], strict = true) {
|
|
19
|
+
this.#strict = strict;
|
|
20
|
+
words.forEach(word => this.add(word));
|
|
21
|
+
}
|
|
13
22
|
|
|
14
23
|
/**
|
|
15
24
|
* Adds a word to the Trie.
|
|
16
25
|
* @param {string} word - The word to add.
|
|
17
26
|
* @returns {boolean} True if the word was added (didn't exist before), false otherwise.
|
|
18
27
|
*/
|
|
19
|
-
|
|
20
|
-
let node = data;
|
|
28
|
+
add(word) {
|
|
29
|
+
let node = this.#data;
|
|
21
30
|
for (let i = 0; i < word.length; ++i) {
|
|
22
31
|
const char = word[i];
|
|
23
|
-
if (!node[MAP]) node[MAP] = new Map();
|
|
24
|
-
const child = node[MAP].get(char) ?? [false];
|
|
25
|
-
node[MAP].set(char, child);
|
|
32
|
+
if (!node[Trie.#MAP]) node[Trie.#MAP] = new Map();
|
|
33
|
+
const child = node[Trie.#MAP].get(char) ?? [false];
|
|
34
|
+
node[Trie.#MAP].set(char, child);
|
|
26
35
|
node = child;
|
|
27
36
|
}
|
|
28
|
-
if (node[HAS]) return false;
|
|
29
|
-
node[HAS] = true;
|
|
37
|
+
if (node[Trie.#HAS]) return false;
|
|
38
|
+
node[Trie.#HAS] = true;
|
|
30
39
|
return true;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#listNodes(word) {
|
|
43
|
+
const nodes = [this.#data];
|
|
34
44
|
for (let i = 0; i < word.length; ++i) {
|
|
35
45
|
const node = nodes.at(-1);
|
|
36
46
|
const char = word[i];
|
|
37
|
-
if (!node[MAP]?.has(char)) {
|
|
47
|
+
if (!node[Trie.#MAP]?.has(char)) {
|
|
38
48
|
nodes.push([false]);
|
|
39
49
|
break;
|
|
40
50
|
}
|
|
41
|
-
nodes.push(node[MAP].get(char));
|
|
51
|
+
nodes.push(node[Trie.#MAP].get(char));
|
|
42
52
|
}
|
|
43
53
|
return nodes;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#findNode(word) {
|
|
57
|
+
return this.#listNodes(word).at(-1);
|
|
58
|
+
}
|
|
48
59
|
|
|
49
60
|
/**
|
|
50
61
|
* Removes a word from the Trie.
|
|
51
62
|
* @param {string} word - The word to remove.
|
|
52
63
|
* @returns {boolean} True if the word was removed, false if it didn't exist.
|
|
53
64
|
*/
|
|
54
|
-
|
|
55
|
-
const nodes = listNodes(word);
|
|
65
|
+
remove(word) {
|
|
66
|
+
const nodes = this.#listNodes(word);
|
|
56
67
|
const rev = nodes.reverse();
|
|
57
|
-
const removed = rev.at(0)[HAS];
|
|
58
|
-
rev.at(0)[HAS] = false;
|
|
59
|
-
if (!strict) return removed;
|
|
68
|
+
const removed = rev.at(0)[Trie.#HAS];
|
|
69
|
+
rev.at(0)[Trie.#HAS] = false;
|
|
70
|
+
if (!this.#strict) return removed;
|
|
60
71
|
for (let i = 0; i < rev.length; ++i) {
|
|
61
72
|
const node = rev[i];
|
|
62
73
|
const first = i === 0;
|
|
63
|
-
const noMap = !node[MAP];
|
|
64
|
-
const size1 = node[MAP]?.size <= 1;
|
|
65
74
|
if (first) {
|
|
66
|
-
if (node[MAP]) break;
|
|
75
|
+
if (node[Trie.#MAP]) break;
|
|
67
76
|
} else {
|
|
68
|
-
if (node[MAP]?.size <= 1) {
|
|
69
|
-
delete node[MAP];
|
|
77
|
+
if (node[Trie.#MAP]?.size <= 1) {
|
|
78
|
+
delete node[Trie.#MAP];
|
|
70
79
|
} else {
|
|
71
80
|
break;
|
|
72
81
|
}
|
|
73
82
|
}
|
|
74
|
-
if (node[HAS]) break;
|
|
83
|
+
if (node[Trie.#HAS]) break;
|
|
75
84
|
}
|
|
76
85
|
return removed;
|
|
77
|
-
}
|
|
86
|
+
}
|
|
78
87
|
|
|
79
88
|
/**
|
|
80
89
|
* Checks if a word exists in the Trie.
|
|
81
90
|
* @param {string} word - The word to check.
|
|
82
91
|
* @returns {boolean} True if the word exists, false otherwise.
|
|
83
92
|
*/
|
|
84
|
-
|
|
93
|
+
has(word) {
|
|
94
|
+
return this.#findNode(word)[Trie.#HAS];
|
|
95
|
+
}
|
|
85
96
|
|
|
86
97
|
/**
|
|
87
98
|
* Returns all words in the Trie that start with the given prefix.
|
|
88
99
|
* @param {string} begin - The prefix to search for.
|
|
89
100
|
* @returns {string[]} An array of words starting with the prefix.
|
|
90
101
|
*/
|
|
91
|
-
|
|
102
|
+
get(begin) {
|
|
92
103
|
const res = [];
|
|
93
104
|
const loop = (node, str = '') => {
|
|
94
105
|
if (!node) return;
|
|
95
|
-
if (node[HAS]) res.push(begin + str);
|
|
96
|
-
const map = node[MAP] || new Map();
|
|
97
|
-
[...map].
|
|
106
|
+
if (node[Trie.#HAS]) res.push(begin + str);
|
|
107
|
+
const map = node[Trie.#MAP] || new Map();
|
|
108
|
+
[...map].forEach(([char, n]) => loop(n, str + char));
|
|
98
109
|
};
|
|
99
|
-
loop(findNode(begin));
|
|
110
|
+
loop(this.#findNode(begin));
|
|
100
111
|
return res;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Returns the internal data structure of the Trie.
|
|
116
|
+
* @returns {Array} The root node of the Trie.
|
|
117
|
+
*/
|
|
118
|
+
getData() {
|
|
119
|
+
return this.#data;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a Map with unique elements and their occurring frequencies.
|
|
3
|
+
* Transforms an array into a Map of (key -> quantity) using an optional mapping callback.
|
|
4
|
+
*
|
|
5
|
+
* @param {Array} arr Target array
|
|
6
|
+
* @param {function} pick Projection callback (defaults to identity function)
|
|
7
|
+
* @returns {Map} Histogram mapping
|
|
8
|
+
*/
|
|
9
|
+
export const arrayHistogram = (iter, pick = el => el) => {
|
|
10
|
+
const quant = new Map();
|
|
11
|
+
for (const obj of iter) {
|
|
12
|
+
const el = pick(obj);
|
|
13
|
+
const cnt = quant.get(el) ?? 0;
|
|
14
|
+
quant.set(el, cnt + 1);
|
|
15
|
+
}
|
|
16
|
+
return quant;
|
|
17
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates all possible combinations of size n from a set of size k without repetition.
|
|
3
|
+
* Yields arrays of indices representing the current combination.
|
|
4
|
+
*
|
|
5
|
+
* Optimized with lexicographic progression to skip invalid states,
|
|
6
|
+
* running in O(1) amortized time per sequence instead of O(k^n).
|
|
7
|
+
*
|
|
8
|
+
* @param {number} n Size of the combination
|
|
9
|
+
* @param {number} k Size of the set to choose from (indices 0 to k-1)
|
|
10
|
+
* @yields {number[]} Array of indices
|
|
11
|
+
*/
|
|
12
|
+
export const combinationsIterator = function* (n, k) {
|
|
13
|
+
if (n > k || n < 0) return;
|
|
14
|
+
const arr = new Array(n).fill(0).map((_, i) => i);
|
|
15
|
+
yield arr.slice();
|
|
16
|
+
|
|
17
|
+
while (true) {
|
|
18
|
+
let i = n - 1;
|
|
19
|
+
while (i >= 0 && arr[i] === k - n + i) {
|
|
20
|
+
i--;
|
|
21
|
+
}
|
|
22
|
+
if (i < 0) break;
|
|
23
|
+
arr[i]++;
|
|
24
|
+
for (let j = i + 1; j < n; j++) {
|
|
25
|
+
arr[j] = arr[j - 1] + 1;
|
|
26
|
+
}
|
|
27
|
+
yield arr.slice();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns all combinations synchronously.
|
|
33
|
+
* WARNING: Calling this with mathematically large sets will overflow local RAM.
|
|
34
|
+
*
|
|
35
|
+
* @param {number} n Size of the combination
|
|
36
|
+
* @param {number} k Size of the set
|
|
37
|
+
* @returns {Array<number[]>} Array containing all combinations
|
|
38
|
+
*/
|
|
39
|
+
export const combinations = (n, k) => {
|
|
40
|
+
return [...combinationsIterator(n, k)];
|
|
41
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal logic for toggling bit state based on MSB progression.
|
|
3
|
+
*/
|
|
4
|
+
const convertBit = (p, v, i) => {
|
|
5
|
+
p[i] = i && p[i-1] ? 1 - v : v;
|
|
6
|
+
return p;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Transforms an array of binary bits into Gray Code.
|
|
11
|
+
*
|
|
12
|
+
* @param {Array<number|boolean>} bits Binary representation (MSB at index 0)
|
|
13
|
+
* @returns {Array<number>} Array of Gray code bits
|
|
14
|
+
*/
|
|
15
|
+
export const bin2gray = (bits) => {
|
|
16
|
+
// Cloning array mathematically to prevent pure-function reference mutation
|
|
17
|
+
return [...bits].reduceRight(convertBit, [...bits]);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Decodes a Gray code array back into standard binary formatting.
|
|
22
|
+
*
|
|
23
|
+
* @param {Array<number|boolean>} gray Gray Code representation
|
|
24
|
+
* @returns {Array<number>} Decoded original binary bits
|
|
25
|
+
*/
|
|
26
|
+
export const gray2bin = (gray) => {
|
|
27
|
+
return [...gray].reduce(convertBit, [...gray]);
|
|
28
|
+
};
|
package/src/heap.mjs
CHANGED
|
@@ -1,72 +1,83 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
* Creates a Min Heap data structure.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @returns {object} The Heap instance with methods.
|
|
3
|
+
* Implemented as a ES6 Class to fix prototyping documentation
|
|
4
|
+
* and properly encapsulate internal mechanics.
|
|
7
5
|
*/
|
|
8
|
-
export
|
|
9
|
-
|
|
6
|
+
export class Heap {
|
|
7
|
+
#arr = [-1];
|
|
8
|
+
#valFn;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initializes the Heap class object.
|
|
12
|
+
* @param {Function} [valFn] - A function to extract the comparison value from an element. Defaults to identity (n => n).
|
|
13
|
+
*/
|
|
14
|
+
constructor(valFn = n => n) {
|
|
15
|
+
this.#valFn = valFn;
|
|
16
|
+
}
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
#up(idx) {
|
|
12
19
|
while (idx > 1) {
|
|
13
20
|
const ni = idx / 2 | 0;
|
|
14
|
-
if (valFn(arr[idx]) < valFn(arr[ni])) {
|
|
15
|
-
[arr[idx], arr[ni]] = [arr[ni], arr[idx]];
|
|
21
|
+
if (this.#valFn(this.#arr[idx]) < this.#valFn(this.#arr[ni])) {
|
|
22
|
+
[this.#arr[idx], this.#arr[ni]] = [this.#arr[ni], this.#arr[idx]];
|
|
16
23
|
}
|
|
17
24
|
idx = ni;
|
|
18
25
|
}
|
|
19
26
|
return idx;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
/**
|
|
24
|
-
* Adds an element to the heap.
|
|
25
|
-
* @param {*} el - The element to add.
|
|
26
|
-
* @returns {number} The new index of the added element.
|
|
27
|
-
*/
|
|
28
|
-
add: el => up(arr.push(el) - 1),
|
|
27
|
+
}
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Adds an element to the heap.
|
|
31
|
+
* @param {*} el - The element to add.
|
|
32
|
+
* @returns {number} The new index of the added element.
|
|
33
|
+
*/
|
|
34
|
+
add(el) {
|
|
35
|
+
return this.#up(this.#arr.push(el) - 1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Removes and returns the minimum element (root) from the heap.
|
|
40
|
+
* @returns {*} The minimum element.
|
|
41
|
+
*/
|
|
42
|
+
take() {
|
|
43
|
+
const len = this.#arr.length;
|
|
44
|
+
if (len <= 1) return [][0];
|
|
45
|
+
let idx = 1;
|
|
46
|
+
const res = this.#arr[idx];
|
|
47
|
+
while (idx < len) {
|
|
48
|
+
const ia = idx * 2;
|
|
49
|
+
const ib = idx * 2 + 1;
|
|
50
|
+
if (ia >= len) break;
|
|
51
|
+
if (ib >= len || this.#valFn(this.#arr[ia]) < this.#valFn(this.#arr[ib])) {
|
|
52
|
+
this.#arr[idx] = this.#arr[ia];
|
|
53
|
+
idx = ia;
|
|
53
54
|
} else {
|
|
54
|
-
arr[idx] = arr
|
|
55
|
-
|
|
55
|
+
this.#arr[idx] = this.#arr[ib];
|
|
56
|
+
idx = ib;
|
|
56
57
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
}
|
|
59
|
+
if (idx === this.#arr.length - 1) {
|
|
60
|
+
this.#arr.pop();
|
|
61
|
+
} else {
|
|
62
|
+
this.#arr[idx] = this.#arr.pop();
|
|
63
|
+
this.#up(idx);
|
|
64
|
+
}
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the number of elements in the heap.
|
|
70
|
+
* @returns {number} The size of the heap.
|
|
71
|
+
*/
|
|
72
|
+
size() {
|
|
73
|
+
return this.#arr.length - 1;
|
|
74
|
+
}
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the internal array representation of the heap (excluding the dummy first element).
|
|
78
|
+
* @returns {Array} The heap elements.
|
|
79
|
+
*/
|
|
80
|
+
data() {
|
|
81
|
+
return this.#arr.slice(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Newton's formula (Binomial Coefficient) n choose k.
|
|
3
|
+
* Evaluates the number of possible combinations.
|
|
4
|
+
* Built strictly on BigInt and optimized iterative fraction reduction
|
|
5
|
+
* to prevent RAM and precision loss during massive factorial expansions.
|
|
6
|
+
*
|
|
7
|
+
* @param {number|bigint|string} n Total elements
|
|
8
|
+
* @param {number|bigint|string} k Elements to pick
|
|
9
|
+
* @returns {bigint} Total possible subset combinations
|
|
10
|
+
*/
|
|
11
|
+
export const nChooseK = (n, k) => {
|
|
12
|
+
const bigN = BigInt(n);
|
|
13
|
+
const bigK = BigInt(k);
|
|
14
|
+
|
|
15
|
+
if (bigK < 0n || bigK > bigN) return 0n;
|
|
16
|
+
if (bigK === 0n || bigK === bigN) return 1n;
|
|
17
|
+
|
|
18
|
+
// Optimization: dynamically reduce the factorial expansion
|
|
19
|
+
// equivalent to (n! / (k! * (n-k)!)), shrinking the multiplication loops.
|
|
20
|
+
const kMin = bigK > (bigN - bigK) ? (bigN - bigK) : bigK;
|
|
21
|
+
|
|
22
|
+
let numerator = 1n;
|
|
23
|
+
let denominator = 1n;
|
|
24
|
+
|
|
25
|
+
for (let i = 1n; i <= kMin; ++i) {
|
|
26
|
+
numerator *= (bigN - i + 1n);
|
|
27
|
+
denominator *= i;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return numerator / denominator;
|
|
31
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a permutations generator from a specified size or an array of elements.
|
|
3
|
+
*
|
|
4
|
+
* @param {number|Array} sizeOrArr Integer size or an array of items
|
|
5
|
+
* @yields {Array} Re-arranged array of items/indices
|
|
6
|
+
*/
|
|
7
|
+
export const permutationsIterator = function*(sizeOrArr) {
|
|
8
|
+
const arr = Array.isArray(sizeOrArr) ? [...sizeOrArr] : new Array(sizeOrArr).fill(0).map((_, i) => i);
|
|
9
|
+
const size = arr.length;
|
|
10
|
+
|
|
11
|
+
const gen = function*(res, used, shift) {
|
|
12
|
+
const len = size - used;
|
|
13
|
+
if (len === 0) {
|
|
14
|
+
yield res;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
for (let i = 0; i < len; ++i) {
|
|
18
|
+
yield* gen([...res, shift[i]], used + 1, [...shift.slice(0, i), ...shift.slice(i + 1)]);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
yield* gen([], 0, arr);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns all permutations synchronously.
|
|
27
|
+
* WARNING: Generates size! (factorial) elements. Scales in O(N!).
|
|
28
|
+
*
|
|
29
|
+
* @param {number|Array} sizeOrArr
|
|
30
|
+
* @returns {Array<Array>} Array of permutation sets
|
|
31
|
+
*/
|
|
32
|
+
export const permutations = (sizeOrArr) => {
|
|
33
|
+
return [...permutationsIterator(sizeOrArr)];
|
|
34
|
+
};
|