diff --git a/README.md b/README.md index 0392aefb..88369406 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ a set of rules that precisely define a sequence of operations. * **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 - * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise and backtracking solutions) + * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise, backtracking, and cascading solutions) * `A` [Permutations](src/algorithms/sets/permutations) (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) diff --git a/src/algorithms/sets/power-set/README.md b/src/algorithms/sets/power-set/README.md index cfe791ae..e96961dd 100644 --- a/src/algorithms/sets/power-set/README.md +++ b/src/algorithms/sets/power-set/README.md @@ -1,7 +1,7 @@ # Power Set 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)`. +empty set and `S` itself. Power set of set `S` is denoted as `P(S)`. For example for `{x, y, z}`, the subsets are: @@ -21,37 +21,37 @@ are: ![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 +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 +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 +> 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 +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 +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. | | `abc` | Subset | | :---: | :---: | :-----------: | | `0` | `000` | `{}` | | `1` | `001` | `{c}` | -| `2` | `010` | `{b}` | +| `2` | `010` | `{b}` | | `3` | `011` | `{c, b}` | | `4` | `100` | `{a}` | | `5` | `101` | `{a, c}` | @@ -68,6 +68,44 @@ element. > See [btPowerSet.js](./btPowerSet.js) file for backtracking solution. +### Cascading Solution + +This is, arguably, the simplest solution to generate a Power Set. + +We start with an empty set: + +```text +powerSets = [[]] +``` + +Now, let's say: + +```text +originalSet = [1, 2, 3] +``` + +Let's add the 1st element from the originalSet to all existing sets: + +```text +[[]] ← 1 = [[], [1]] +``` + +Adding the 2nd element to all existing sets: + +```text +[[], [1]] ← 2 = [[], [1], [2], [1, 2]] +``` + +Adding the 3nd element to all existing sets: + +``` +[[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] +``` + +And so on, for the rest of the elements from the `originalSet`. On every iteration the number of sets is doubled, so we'll get `2^n` sets. + +> See [caPowerSet.js](./caPowerSet.js) file for cascading solution. + ## References * [Wikipedia](https://en.wikipedia.org/wiki/Power_set) diff --git a/src/algorithms/sets/power-set/__test__/caPowerSet.test.js b/src/algorithms/sets/power-set/__test__/caPowerSet.test.js new file mode 100644 index 00000000..4fad5efe --- /dev/null +++ b/src/algorithms/sets/power-set/__test__/caPowerSet.test.js @@ -0,0 +1,28 @@ +import caPowerSet from '../caPowerSet'; + +describe('caPowerSet', () => { + it('should calculate power set of given set using cascading approach', () => { + expect(caPowerSet([1])).toEqual([ + [], + [1], + ]); + + expect(caPowerSet([1, 2])).toEqual([ + [], + [1], + [2], + [1, 2], + ]); + + expect(caPowerSet([1, 2, 3])).toEqual([ + [], + [1], + [2], + [1, 2], + [3], + [1, 3], + [2, 3], + [1, 2, 3], + ]); + }); +}); diff --git a/src/algorithms/sets/power-set/caPowerSet.js b/src/algorithms/sets/power-set/caPowerSet.js new file mode 100644 index 00000000..45b9eb61 --- /dev/null +++ b/src/algorithms/sets/power-set/caPowerSet.js @@ -0,0 +1,37 @@ +/** + * Find power-set of a set using CASCADING approach. + * + * @param {*[]} originalSet + * @return {*[][]} + */ +export default function caPowerSet(originalSet) { + // Let's start with an empty set. + const sets = [[]]; + + /* + Now, let's say: + originalSet = [1, 2, 3]. + + Let's add the first element from the originalSet to all existing sets: + [[]] ← 1 = [[], [1]] + + Adding the 2nd element to all existing sets: + [[], [1]] ← 2 = [[], [1], [2], [1, 2]] + + Adding the 3nd element to all existing sets: + [[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] + + And so on for the rest of the elements from originalSet. + On every iteration the number of sets is doubled, so we'll get 2^n sets. + */ + for (let numIdx = 0; numIdx < originalSet.length; numIdx += 1) { + const existingSetsNum = sets.length; + + for (let setIdx = 0; setIdx < existingSetsNum; setIdx += 1) { + const set = [...sets[setIdx], originalSet[numIdx]]; + sets.push(set); + } + } + + return sets; +}