mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2026-03-13 08:51:02 +08:00
Restructure folders.
This commit is contained in:
42
src/algorithms/sets/permutations/README.md
Normal file
42
src/algorithms/sets/permutations/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Permutations
|
||||
|
||||
When the order doesn't matter, it is a **Combination**.
|
||||
|
||||
When the order **does** matter it is a **Permutation**.
|
||||
|
||||
**"The combination to the safe is 472"**. We do care about the order. `724` won't work, nor will `247`.
|
||||
It has to be exactly `4-7-2`.
|
||||
|
||||
## Permutations without repetitions
|
||||
|
||||
A permutation, also called an “arrangement number” or “order”, is a rearrangement of
|
||||
the elements of an ordered list `S` into a one-to-one correspondence with `S` itself.
|
||||
|
||||
Below are the permutations of string `ABC`.
|
||||
|
||||
`ABC ACB BAC BCA CBA CAB`
|
||||
|
||||
Or for example the first three people in a running race: you can't be first and second.
|
||||
|
||||
**Number of combinations**
|
||||
|
||||
```
|
||||
n * (n-1) * (n -2) * ... * 1 = n!
|
||||
```
|
||||
|
||||
## Permutations with repetitions
|
||||
|
||||
When repetition is allowed we have permutations with repetitions.
|
||||
For example the the lock below: it could be `333`.
|
||||
|
||||

|
||||
|
||||
**Number of combinations**
|
||||
|
||||
```
|
||||
n * n * n ... (r times) = n^r
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
[Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)
|
||||
@@ -0,0 +1,55 @@
|
||||
import permutateWithRepetitions from '../permutateWithRepetitions';
|
||||
|
||||
describe('permutateWithRepetitions', () => {
|
||||
it('should permutate string with repetition', () => {
|
||||
const permutations0 = permutateWithRepetitions([]);
|
||||
expect(permutations0).toEqual([]);
|
||||
|
||||
const permutations1 = permutateWithRepetitions(['A']);
|
||||
expect(permutations1).toEqual([
|
||||
['A'],
|
||||
]);
|
||||
|
||||
const permutations2 = permutateWithRepetitions(['A', 'B']);
|
||||
expect(permutations2).toEqual([
|
||||
['A', 'A'],
|
||||
['A', 'B'],
|
||||
['B', 'A'],
|
||||
['B', 'B'],
|
||||
]);
|
||||
|
||||
const permutations3 = permutateWithRepetitions(['A', 'B', 'C']);
|
||||
expect(permutations3).toEqual([
|
||||
['A', 'A', 'A'],
|
||||
['A', 'A', 'B'],
|
||||
['A', 'A', 'C'],
|
||||
['A', 'B', 'A'],
|
||||
['A', 'B', 'B'],
|
||||
['A', 'B', 'C'],
|
||||
['A', 'C', 'A'],
|
||||
['A', 'C', 'B'],
|
||||
['A', 'C', 'C'],
|
||||
['B', 'A', 'A'],
|
||||
['B', 'A', 'B'],
|
||||
['B', 'A', 'C'],
|
||||
['B', 'B', 'A'],
|
||||
['B', 'B', 'B'],
|
||||
['B', 'B', 'C'],
|
||||
['B', 'C', 'A'],
|
||||
['B', 'C', 'B'],
|
||||
['B', 'C', 'C'],
|
||||
['C', 'A', 'A'],
|
||||
['C', 'A', 'B'],
|
||||
['C', 'A', 'C'],
|
||||
['C', 'B', 'A'],
|
||||
['C', 'B', 'B'],
|
||||
['C', 'B', 'C'],
|
||||
['C', 'C', 'A'],
|
||||
['C', 'C', 'B'],
|
||||
['C', 'C', 'C'],
|
||||
]);
|
||||
|
||||
const permutations4 = permutateWithRepetitions(['A', 'B', 'C', 'D']);
|
||||
expect(permutations4.length).toBe(4 * 4 * 4 * 4);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import permutateWithoutRepetitions from '../permutateWithoutRepetitions';
|
||||
import factorial from '../../../math/factorial/factorial';
|
||||
|
||||
describe('permutateWithoutRepetitions', () => {
|
||||
it('should permutate string', () => {
|
||||
const permutations0 = permutateWithoutRepetitions([]);
|
||||
expect(permutations0).toEqual([]);
|
||||
|
||||
const permutations1 = permutateWithoutRepetitions(['A']);
|
||||
expect(permutations1).toEqual([
|
||||
['A'],
|
||||
]);
|
||||
|
||||
const permutations2 = permutateWithoutRepetitions(['A', 'B']);
|
||||
expect(permutations2.length).toBe(2);
|
||||
expect(permutations2).toEqual([
|
||||
['B', 'A'],
|
||||
['A', 'B'],
|
||||
]);
|
||||
|
||||
const permutations6 = permutateWithoutRepetitions(['A', 'A']);
|
||||
expect(permutations6.length).toBe(2);
|
||||
expect(permutations6).toEqual([
|
||||
['A', 'A'],
|
||||
['A', 'A'],
|
||||
]);
|
||||
|
||||
const permutations3 = permutateWithoutRepetitions(['A', 'B', 'C']);
|
||||
expect(permutations3.length).toBe(factorial(3));
|
||||
expect(permutations3).toEqual([
|
||||
['C', 'B', 'A'],
|
||||
['B', 'C', 'A'],
|
||||
['B', 'A', 'C'],
|
||||
['C', 'A', 'B'],
|
||||
['A', 'C', 'B'],
|
||||
['A', 'B', 'C'],
|
||||
]);
|
||||
|
||||
const permutations4 = permutateWithoutRepetitions(['A', 'B', 'C', 'D']);
|
||||
expect(permutations4.length).toBe(factorial(4));
|
||||
expect(permutations4).toEqual([
|
||||
['D', 'C', 'B', 'A'],
|
||||
['C', 'D', 'B', 'A'],
|
||||
['C', 'B', 'D', 'A'],
|
||||
['C', 'B', 'A', 'D'],
|
||||
['D', 'B', 'C', 'A'],
|
||||
['B', 'D', 'C', 'A'],
|
||||
['B', 'C', 'D', 'A'],
|
||||
['B', 'C', 'A', 'D'],
|
||||
['D', 'B', 'A', 'C'],
|
||||
['B', 'D', 'A', 'C'],
|
||||
['B', 'A', 'D', 'C'],
|
||||
['B', 'A', 'C', 'D'],
|
||||
['D', 'C', 'A', 'B'],
|
||||
['C', 'D', 'A', 'B'],
|
||||
['C', 'A', 'D', 'B'],
|
||||
['C', 'A', 'B', 'D'],
|
||||
['D', 'A', 'C', 'B'],
|
||||
['A', 'D', 'C', 'B'],
|
||||
['A', 'C', 'D', 'B'],
|
||||
['A', 'C', 'B', 'D'],
|
||||
['D', 'A', 'B', 'C'],
|
||||
['A', 'D', 'B', 'C'],
|
||||
['A', 'B', 'D', 'C'],
|
||||
['A', 'B', 'C', 'D'],
|
||||
]);
|
||||
|
||||
const permutations5 = permutateWithoutRepetitions(['A', 'B', 'C', 'D', 'E', 'F']);
|
||||
expect(permutations5.length).toBe(factorial(6));
|
||||
});
|
||||
});
|
||||
42
src/algorithms/sets/permutations/permutateWithRepetitions.js
Normal file
42
src/algorithms/sets/permutations/permutateWithRepetitions.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @param {*[]} permutationOptions
|
||||
* @return {*[]}
|
||||
*/
|
||||
export default function permutateWithRepetitions(permutationOptions) {
|
||||
// There is no permutations for empty array.
|
||||
if (!permutationOptions || permutationOptions.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// There is only one permutation for the 1-element array.
|
||||
if (permutationOptions.length === 1) {
|
||||
return [permutationOptions];
|
||||
}
|
||||
|
||||
// Let's create initial set of permutations.
|
||||
let previousPermutations = permutationOptions.map(option => [option]);
|
||||
let currentPermutations = [];
|
||||
let permutationSize = 1;
|
||||
|
||||
// While the size of each permutation is less then or equal to options length...
|
||||
while (permutationSize < permutationOptions.length) {
|
||||
// Reset all current permutations.
|
||||
currentPermutations = [];
|
||||
|
||||
for (let permIndex = 0; permIndex < previousPermutations.length; permIndex += 1) {
|
||||
for (let optionIndex = 0; optionIndex < permutationOptions.length; optionIndex += 1) {
|
||||
let currentPermutation = previousPermutations[permIndex];
|
||||
currentPermutation = currentPermutation.concat([permutationOptions[optionIndex]]);
|
||||
currentPermutations.push(currentPermutation);
|
||||
}
|
||||
}
|
||||
|
||||
// Make current permutations to be the previous ones.
|
||||
previousPermutations = currentPermutations.slice(0);
|
||||
|
||||
// Increase permutation size counter.
|
||||
permutationSize += 1;
|
||||
}
|
||||
|
||||
return currentPermutations;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @param {*[]} permutationOptions
|
||||
* @return {*[]}
|
||||
*/
|
||||
export default function permutateWithoutRepetitions(permutationOptions) {
|
||||
if (permutationOptions.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (permutationOptions.length === 1) {
|
||||
return [permutationOptions];
|
||||
}
|
||||
|
||||
const permutations = [];
|
||||
|
||||
// Get all permutations of length (n - 1).
|
||||
const previousOptions = permutationOptions.slice(0, permutationOptions.length - 1);
|
||||
const previousPermutations = permutateWithoutRepetitions(previousOptions);
|
||||
|
||||
// Insert last option into every possible position of every previous permutation.
|
||||
const lastOption = permutationOptions.slice(permutationOptions.length - 1);
|
||||
|
||||
for (
|
||||
let permutationIndex = 0;
|
||||
permutationIndex < previousPermutations.length;
|
||||
permutationIndex += 1
|
||||
) {
|
||||
const currentPermutation = previousPermutations[permutationIndex];
|
||||
|
||||
// Insert last option into every possible position of currentPermutation.
|
||||
for (let positionIndex = 0; positionIndex <= currentPermutation.length; positionIndex += 1) {
|
||||
const permutationPrefix = currentPermutation.slice(0, positionIndex);
|
||||
const permutationSuffix = currentPermutation.slice(positionIndex);
|
||||
permutations.push(permutationPrefix.concat(lastOption, permutationSuffix));
|
||||
}
|
||||
}
|
||||
|
||||
return permutations;
|
||||
}
|
||||
Reference in New Issue
Block a user