mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-14 06:52:59 +08:00
Add backtracking solution for finding the power-set of a set.
This commit is contained in:
parent
bffacf0707
commit
5eb1195c61
@ -77,7 +77,7 @@ a set of rules that precisely define a sequence of operations.
|
|||||||
* **Sets**
|
* **Sets**
|
||||||
* `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets
|
* `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets
|
||||||
* `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
|
* `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
|
||||||
* `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
|
* `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise and backtracking solutions)
|
||||||
* `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
|
* `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
|
||||||
* `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
|
* `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
|
||||||
* `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
|
* `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
|
||||||
@ -190,6 +190,7 @@ if it satisfies all conditions, and only then continue generating subsequent sol
|
|||||||
different path of finding a solution. Normally the DFS traversal of state-space is being used.
|
different path of finding a solution. Normally the DFS traversal of state-space is being used.
|
||||||
* `B` [Jump Game](src/algorithms/uncategorized/jump-game)
|
* `B` [Jump Game](src/algorithms/uncategorized/jump-game)
|
||||||
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
|
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
|
||||||
|
* `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
|
||||||
* `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
|
* `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
|
||||||
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
|
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
|
||||||
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
|
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
|
||||||
|
@ -1,11 +1,62 @@
|
|||||||
# Power Set
|
# Power Set
|
||||||
|
|
||||||
Power set of a set A is the set of all of the subsets of A.
|
Power set of a set `S` is the set of all of the subsets of `S`, including the
|
||||||
|
empty set and `S` itself. Power set of set `S` is denoted as `P(S)`.
|
||||||
|
|
||||||
Eg. for `{x, y, z}`, the subsets are : `{{}, {x}, {y}, {z}, {x, y}, {x, z}, {y, z}, {x, y, z}}`
|
For example for `{x, y, z}`, the subsets
|
||||||
|
are:
|
||||||
|
|
||||||
|
```text
|
||||||
|
{
|
||||||
|
{}, // (also denoted empty set ∅ or the null set)
|
||||||
|
{x},
|
||||||
|
{y},
|
||||||
|
{z},
|
||||||
|
{x, y},
|
||||||
|
{x, z},
|
||||||
|
{y, z},
|
||||||
|
{x, y, z}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
![Power Set](https://www.mathsisfun.com/sets/images/power-set.svg)
|
![Power Set](https://www.mathsisfun.com/sets/images/power-set.svg)
|
||||||
|
|
||||||
|
Here is how we may illustrate the elements of the power set of the set `{x, y, z}` ordered with respect to
|
||||||
|
inclusion:
|
||||||
|
|
||||||
|
![](https://upload.wikimedia.org/wikipedia/commons/e/ea/Hasse_diagram_of_powerset_of_3.svg)
|
||||||
|
|
||||||
|
**Number of Subsets**
|
||||||
|
|
||||||
|
If `S` is a finite set with `|S| = n` elements, then the number of subsets
|
||||||
|
of `S` is `|P(S)| = 2^n`. This fact, which is the motivation for the
|
||||||
|
notation `2^S`, may be demonstrated simply as follows:
|
||||||
|
|
||||||
|
> First, order the elements of `S` in any manner. We write any subset of `S` in
|
||||||
|
the format `{γ1, γ2, ..., γn}` where `γi , 1 ≤ i ≤ n`, can take the value
|
||||||
|
of `0` or `1`. If `γi = 1`, the `i`-th element of `S` is in the subset;
|
||||||
|
otherwise, the `i`-th element is not in the subset. Clearly the number of
|
||||||
|
distinct subsets that can be constructed this way is `2^n` as `γi ∈ {0, 1}`.
|
||||||
|
|
||||||
|
## Algorithms
|
||||||
|
|
||||||
|
### Bitwise Solution
|
||||||
|
|
||||||
|
Each number in binary representation in a range from `0` to `2^n` does exactly
|
||||||
|
what we need: it shows by its bits (`0` or `1`) whether to include related
|
||||||
|
element from the set or not. For example, for the set `{1, 2, 3}` the binary
|
||||||
|
number of `0b010` would mean that we need to include only `2` to the current set.
|
||||||
|
|
||||||
|
> See [bwPowerSet.js](./bwPowerSet.js) file for bitwise solution.
|
||||||
|
|
||||||
|
### Backtracking Solution
|
||||||
|
|
||||||
|
In backtracking approach we're constantly trying to add next element of the set
|
||||||
|
to the subset, memorizing it and then removing it and try the same with the next
|
||||||
|
element.
|
||||||
|
|
||||||
|
> See [btPowerSet.js](./btPowerSet.js) file for backtracking solution.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
* [Wikipedia](https://en.wikipedia.org/wiki/Power_set)
|
* [Wikipedia](https://en.wikipedia.org/wiki/Power_set)
|
||||||
|
21
src/algorithms/sets/power-set/__test__/btPowerSet.test.js
Normal file
21
src/algorithms/sets/power-set/__test__/btPowerSet.test.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import btPowerSet from '../btPowerSet';
|
||||||
|
|
||||||
|
describe('btPowerSet', () => {
|
||||||
|
it('should calculate power set of given set using backtracking approach', () => {
|
||||||
|
expect(btPowerSet([1])).toEqual([
|
||||||
|
[],
|
||||||
|
[1],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(btPowerSet([1, 2, 3])).toEqual([
|
||||||
|
[],
|
||||||
|
[1],
|
||||||
|
[1, 2],
|
||||||
|
[1, 2, 3],
|
||||||
|
[1, 3],
|
||||||
|
[2],
|
||||||
|
[2, 3],
|
||||||
|
[3],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
21
src/algorithms/sets/power-set/__test__/bwPowerSet.test.js
Normal file
21
src/algorithms/sets/power-set/__test__/bwPowerSet.test.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import bwPowerSet from '../bwPowerSet';
|
||||||
|
|
||||||
|
describe('bwPowerSet', () => {
|
||||||
|
it('should calculate power set of given set using bitwise approach', () => {
|
||||||
|
expect(bwPowerSet([1])).toEqual([
|
||||||
|
[],
|
||||||
|
[1],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(bwPowerSet([1, 2, 3])).toEqual([
|
||||||
|
[],
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[1, 2],
|
||||||
|
[3],
|
||||||
|
[1, 3],
|
||||||
|
[2, 3],
|
||||||
|
[1, 2, 3],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
@ -1,24 +0,0 @@
|
|||||||
import powerSet from '../powerSet';
|
|
||||||
|
|
||||||
describe('powerSet', () => {
|
|
||||||
it('should calculate power set of given set', () => {
|
|
||||||
const powerSets1 = powerSet([1]);
|
|
||||||
const powerSets2 = powerSet([1, 2, 3]);
|
|
||||||
|
|
||||||
expect(powerSets1).toEqual([
|
|
||||||
[],
|
|
||||||
[1],
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(powerSets2).toEqual([
|
|
||||||
[],
|
|
||||||
[1],
|
|
||||||
[2],
|
|
||||||
[1, 2],
|
|
||||||
[3],
|
|
||||||
[1, 3],
|
|
||||||
[2, 3],
|
|
||||||
[1, 2, 3],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
34
src/algorithms/sets/power-set/btPowerSet.js
Normal file
34
src/algorithms/sets/power-set/btPowerSet.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* @param {*[]} originalSet - Original set of elements we're forming power-set of.
|
||||||
|
* @param {*[][]} allSubsets - All subsets that have been formed so far.
|
||||||
|
* @param {*[]} currentSubSet - Current subset that we're forming at the moment.
|
||||||
|
* @param {number} startAt - The position of in original set we're starting to form current subset.
|
||||||
|
* @return {*[][]} - All subsets of original set.
|
||||||
|
*/
|
||||||
|
function btPowerSetRecursive(originalSet, allSubsets = [[]], currentSubSet = [], startAt = 0) {
|
||||||
|
// In order to avoid duplication we need to start from next element every time we're forming a
|
||||||
|
// subset. If we will start from zero then we'll have duplicates like {3, 3, 3}.
|
||||||
|
for (let position = startAt; position < originalSet.length; position += 1) {
|
||||||
|
// Let's push current element to the subset.
|
||||||
|
currentSubSet.push(originalSet[position]);
|
||||||
|
// Current subset is already valid so let's memorize it.
|
||||||
|
allSubsets.push([...currentSubSet]);
|
||||||
|
// Let's try to form all other subsets for the current subset.
|
||||||
|
btPowerSetRecursive(originalSet, allSubsets, currentSubSet, position + 1);
|
||||||
|
// BACKTRACK. Exclude last element from the subset and try the next one.
|
||||||
|
currentSubSet.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return all subsets of a set.
|
||||||
|
return allSubsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find power-set of a set using BACKTRACKING approach.
|
||||||
|
*
|
||||||
|
* @param {*[]} originalSet
|
||||||
|
* @return {*[][]}
|
||||||
|
*/
|
||||||
|
export default function btPowerSet(originalSet) {
|
||||||
|
return btPowerSetRecursive(originalSet);
|
||||||
|
}
|
@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Find power-set of a set using BITWISE approach.
|
||||||
|
*
|
||||||
|
* @param {*[]} originalSet
|
||||||
|
* @return {*[][]}
|
||||||
|
*/
|
||||||
export default function powerSet(originalSet) {
|
export default function powerSet(originalSet) {
|
||||||
const subSets = [];
|
const subSets = [];
|
||||||
|
|
||||||
@ -7,8 +13,8 @@ export default function powerSet(originalSet) {
|
|||||||
const numberOfCombinations = 2 ** originalSet.length;
|
const numberOfCombinations = 2 ** originalSet.length;
|
||||||
|
|
||||||
// Each number in binary representation in a range from 0 to 2^n does exactly what we need:
|
// Each number in binary representation in a range from 0 to 2^n does exactly what we need:
|
||||||
// it shoes by its bits (0 or 1) whether to include related element from the set or not.
|
// it shows by its bits (0 or 1) whether to include related element from the set or not.
|
||||||
// For example, for the set {1, 2, 3} the binary number of 010 would mean that we need to
|
// For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
|
||||||
// include only "2" to the current set.
|
// include only "2" to the current set.
|
||||||
for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
|
for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
|
||||||
const subSet = [];
|
const subSet = [];
|
Loading…
Reference in New Issue
Block a user