diff --git a/.eslintrc b/.eslintrc index 634529e0..3790cd52 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,5 +4,8 @@ "plugins": ["jest"], "env": { "jest/globals": true + }, + "rules": { + "no-bitwise": "off" } } diff --git a/README.md b/README.md index 63a02f2b..f5ffe8ad 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ * Math * [Fibonacci Number](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) * [Cartesian Product](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/cartesian-product) + * [Power Set](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/power-set) ## Running Tests diff --git a/src/algorithms/math/power-set/README.md b/src/algorithms/math/power-set/README.md new file mode 100644 index 00000000..0857e680 --- /dev/null +++ b/src/algorithms/math/power-set/README.md @@ -0,0 +1,5 @@ +# Power Set + +Power set of a set A is the set of all of the subsets of A. + +Eg. for `{x, y, z}`, the subsets are : `{{}, {x}, {y}, {z}, {x, y}, {x, z}, {y, z}, {x, y, z}}` diff --git a/src/algorithms/math/power-set/__test__/powerSet.test.js b/src/algorithms/math/power-set/__test__/powerSet.test.js new file mode 100644 index 00000000..26195081 --- /dev/null +++ b/src/algorithms/math/power-set/__test__/powerSet.test.js @@ -0,0 +1,24 @@ +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], + ]); + }); +}); diff --git a/src/algorithms/math/power-set/powerSet.js b/src/algorithms/math/power-set/powerSet.js new file mode 100644 index 00000000..8619f32e --- /dev/null +++ b/src/algorithms/math/power-set/powerSet.js @@ -0,0 +1,28 @@ +export default function powerSet(originalSet) { + const subSets = []; + + // We will have 2^n possible combinations (where n is a length of original set). + // It is because for every element of original set we will decide whether to include + // it or not (2 options for each set element). + const numberOfCombinations = 2 ** originalSet.length; + + // 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. + // For example, for the set {1, 2, 3} the binary number of 010 would mean that we need to + // include only "2" to the current set. + for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) { + const subSet = []; + + for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) { + // Decide whether we need to include current element into the subset or not. + if (combinationIndex & (1 << setElementIndex)) { + subSet.push(originalSet[setElementIndex]); + } + } + + // Add current subset to the list of all subsets. + subSets.push(subSet); + } + + return subSets; +}