Skip to content

Commit 5eb1195

Browse files
committedAug 21, 2018
Add backtracking solution for finding the power-set of a set.
1 parent bffacf0 commit 5eb1195

File tree

7 files changed

+139
-29
lines changed

7 files changed

+139
-29
lines changed
 

‎README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ a set of rules that precisely define a sequence of operations.
7777
* **Sets**
7878
* `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets
7979
* `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
80-
* `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
80+
* `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise and backtracking solutions)
8181
* `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
8282
* `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
8383
* `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
190190
different path of finding a solution. Normally the DFS traversal of state-space is being used.
191191
* `B` [Jump Game](src/algorithms/uncategorized/jump-game)
192192
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
193+
* `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
193194
* `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
194195
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
195196
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)

‎src/algorithms/sets/power-set/README.md

+53-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,62 @@
11
# Power Set
22

3-
Power set of a set A is the set of all of the subsets of A.
3+
Power set of a set `S` is the set of all of the subsets of `S`, including the
4+
empty set and `S` itself. Power set of set `S` is denoted as `P(S)`.
45

5-
Eg. for `{x, y, z}`, the subsets are : `{{}, {x}, {y}, {z}, {x, y}, {x, z}, {y, z}, {x, y, z}}`
6+
For example for `{x, y, z}`, the subsets
7+
are:
8+
9+
```text
10+
{
11+
{}, // (also denoted empty set ∅ or the null set)
12+
{x},
13+
{y},
14+
{z},
15+
{x, y},
16+
{x, z},
17+
{y, z},
18+
{x, y, z}
19+
}
20+
```
621

722
![Power Set](https://www.mathsisfun.com/sets/images/power-set.svg)
823

24+
Here is how we may illustrate the elements of the power set of the set `{x, y, z}` ordered with respect to
25+
inclusion:
26+
27+
![](https://upload.wikimedia.org/wikipedia/commons/e/ea/Hasse_diagram_of_powerset_of_3.svg)
28+
29+
**Number of Subsets**
30+
31+
If `S` is a finite set with `|S| = n` elements, then the number of subsets
32+
of `S` is `|P(S)| = 2^n`. This fact, which is the motivation for the
33+
notation `2^S`, may be demonstrated simply as follows:
34+
35+
> First, order the elements of `S` in any manner. We write any subset of `S` in
36+
the format `{γ1, γ2, ..., γn}` where `γi , 1 ≤ i ≤ n`, can take the value
37+
of `0` or `1`. If `γi = 1`, the `i`-th element of `S` is in the subset;
38+
otherwise, the `i`-th element is not in the subset. Clearly the number of
39+
distinct subsets that can be constructed this way is `2^n` as `γi ∈ {0, 1}`.
40+
41+
## Algorithms
42+
43+
### Bitwise Solution
44+
45+
Each number in binary representation in a range from `0` to `2^n` does exactly
46+
what we need: it shows by its bits (`0` or `1`) whether to include related
47+
element from the set or not. For example, for the set `{1, 2, 3}` the binary
48+
number of `0b010` would mean that we need to include only `2` to the current set.
49+
50+
> See [bwPowerSet.js](./bwPowerSet.js) file for bitwise solution.
51+
52+
### Backtracking Solution
53+
54+
In backtracking approach we're constantly trying to add next element of the set
55+
to the subset, memorizing it and then removing it and try the same with the next
56+
element.
57+
58+
> See [btPowerSet.js](./btPowerSet.js) file for backtracking solution.
59+
960
## References
1061

1162
* [Wikipedia](https://en.wikipedia.org/wiki/Power_set)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import btPowerSet from '../btPowerSet';
2+
3+
describe('btPowerSet', () => {
4+
it('should calculate power set of given set using backtracking approach', () => {
5+
expect(btPowerSet([1])).toEqual([
6+
[],
7+
[1],
8+
]);
9+
10+
expect(btPowerSet([1, 2, 3])).toEqual([
11+
[],
12+
[1],
13+
[1, 2],
14+
[1, 2, 3],
15+
[1, 3],
16+
[2],
17+
[2, 3],
18+
[3],
19+
]);
20+
});
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import bwPowerSet from '../bwPowerSet';
2+
3+
describe('bwPowerSet', () => {
4+
it('should calculate power set of given set using bitwise approach', () => {
5+
expect(bwPowerSet([1])).toEqual([
6+
[],
7+
[1],
8+
]);
9+
10+
expect(bwPowerSet([1, 2, 3])).toEqual([
11+
[],
12+
[1],
13+
[2],
14+
[1, 2],
15+
[3],
16+
[1, 3],
17+
[2, 3],
18+
[1, 2, 3],
19+
]);
20+
});
21+
});

‎src/algorithms/sets/power-set/__test__/powerSet.test.js

-24
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @param {*[]} originalSet - Original set of elements we're forming power-set of.
3+
* @param {*[][]} allSubsets - All subsets that have been formed so far.
4+
* @param {*[]} currentSubSet - Current subset that we're forming at the moment.
5+
* @param {number} startAt - The position of in original set we're starting to form current subset.
6+
* @return {*[][]} - All subsets of original set.
7+
*/
8+
function btPowerSetRecursive(originalSet, allSubsets = [[]], currentSubSet = [], startAt = 0) {
9+
// In order to avoid duplication we need to start from next element every time we're forming a
10+
// subset. If we will start from zero then we'll have duplicates like {3, 3, 3}.
11+
for (let position = startAt; position < originalSet.length; position += 1) {
12+
// Let's push current element to the subset.
13+
currentSubSet.push(originalSet[position]);
14+
// Current subset is already valid so let's memorize it.
15+
allSubsets.push([...currentSubSet]);
16+
// Let's try to form all other subsets for the current subset.
17+
btPowerSetRecursive(originalSet, allSubsets, currentSubSet, position + 1);
18+
// BACKTRACK. Exclude last element from the subset and try the next one.
19+
currentSubSet.pop();
20+
}
21+
22+
// Return all subsets of a set.
23+
return allSubsets;
24+
}
25+
26+
/**
27+
* Find power-set of a set using BACKTRACKING approach.
28+
*
29+
* @param {*[]} originalSet
30+
* @return {*[][]}
31+
*/
32+
export default function btPowerSet(originalSet) {
33+
return btPowerSetRecursive(originalSet);
34+
}

‎src/algorithms/sets/power-set/powerSet.js ‎src/algorithms/sets/power-set/bwPowerSet.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* Find power-set of a set using BITWISE approach.
3+
*
4+
* @param {*[]} originalSet
5+
* @return {*[][]}
6+
*/
17
export default function powerSet(originalSet) {
28
const subSets = [];
39

@@ -7,8 +13,8 @@ export default function powerSet(originalSet) {
713
const numberOfCombinations = 2 ** originalSet.length;
814

915
// Each number in binary representation in a range from 0 to 2^n does exactly what we need:
10-
// it shoes by its bits (0 or 1) whether to include related element from the set or not.
11-
// For example, for the set {1, 2, 3} the binary number of 010 would mean that we need to
16+
// it shows by its bits (0 or 1) whether to include related element from the set or not.
17+
// For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
1218
// include only "2" to the current set.
1319
for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
1420
const subSet = [];

0 commit comments

Comments
 (0)
Please sign in to comment.