From b87839062aca7fe9216a6ff7255081dd4b2e4873 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 7 Jul 2018 11:11:20 +0300 Subject: [PATCH] Add Pascal's triangle. --- src/algorithms/math/pascal-triangle/README.md | 27 ++++++++++++++++++- .../__test__/pascalTriangle.test.js | 14 ++++++++++ .../math/pascal-triangle/pascalTriangle.js | 16 +++++++++++ .../pascalTriangleRecursive.js | 2 +- .../combineWithoutRepetitions.test.js | 4 +++ 5 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/algorithms/math/pascal-triangle/__test__/pascalTriangle.test.js create mode 100644 src/algorithms/math/pascal-triangle/pascalTriangle.js diff --git a/src/algorithms/math/pascal-triangle/README.md b/src/algorithms/math/pascal-triangle/README.md index 523a9792..ff507541 100644 --- a/src/algorithms/math/pascal-triangle/README.md +++ b/src/algorithms/math/pascal-triangle/README.md @@ -1,7 +1,7 @@ # Pascal's Triangle In mathematics, **Pascal's triangle** is a triangular array of -the binomial coefficients. +the [binomial coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient). The rows of Pascal's triangle are conventionally enumerated starting with row `n = 0` at the top (the `0th` row). The @@ -34,6 +34,31 @@ paragraph may be written as follows: for any non-negative integer `n` and any integer `k` between `0` and `n`, inclusive. +![Binomial Coefficient](https://wikimedia.org/api/rest_v1/media/math/render/svg/a2457a7ef3c77831e34e06a1fe17a80b84a03181) + +## Calculating triangle entries in O(n) time + +We know that `i`-th entry in a line number `lineNumber` is +Binomial Coefficient `C(lineNumber, i)` and all lines start +with value `1`. The idea is to +calculate `C(lineNumber, i)` using `C(lineNumber, i-1)`. It +can be calculated in `O(1)` time using the following: + +``` +C(lineNumber, i) = lineNumber! / ((lineNumber - i)! * i!) +C(lineNumber, i - 1) = lineNumber! / ((lineNumber - i + 1)! * (i - 1)!) +``` + +We can derive following expression from above two expressions: + +``` +C(lineNumber, i) = C(lineNumber, i - 1) * (lineNumber - i + 1) / i +``` + +So `C(lineNumber, i)` can be calculated +from `C(lineNumber, i - 1)` in `O(1)` time. + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Pascal%27s_triangle) +- [GeeksForGeeks](https://www.geeksforgeeks.org/pascal-triangle/) diff --git a/src/algorithms/math/pascal-triangle/__test__/pascalTriangle.test.js b/src/algorithms/math/pascal-triangle/__test__/pascalTriangle.test.js new file mode 100644 index 00000000..152fc8ea --- /dev/null +++ b/src/algorithms/math/pascal-triangle/__test__/pascalTriangle.test.js @@ -0,0 +1,14 @@ +import pascalTriangle from '../pascalTriangle'; + +describe('pascalTriangle', () => { + it('should calculate Pascal Triangle coefficients for specific line number', () => { + expect(pascalTriangle(0)).toEqual([1]); + expect(pascalTriangle(1)).toEqual([1, 1]); + expect(pascalTriangle(2)).toEqual([1, 2, 1]); + expect(pascalTriangle(3)).toEqual([1, 3, 3, 1]); + expect(pascalTriangle(4)).toEqual([1, 4, 6, 4, 1]); + expect(pascalTriangle(5)).toEqual([1, 5, 10, 10, 5, 1]); + expect(pascalTriangle(6)).toEqual([1, 6, 15, 20, 15, 6, 1]); + expect(pascalTriangle(7)).toEqual([1, 7, 21, 35, 35, 21, 7, 1]); + }); +}); diff --git a/src/algorithms/math/pascal-triangle/pascalTriangle.js b/src/algorithms/math/pascal-triangle/pascalTriangle.js new file mode 100644 index 00000000..5842e720 --- /dev/null +++ b/src/algorithms/math/pascal-triangle/pascalTriangle.js @@ -0,0 +1,16 @@ +/** + * @param {number} lineNumber - zero based. + * @return {number[]} + */ +export default function pascalTriangle(lineNumber) { + const currentLine = [1]; + + const currentLineSize = lineNumber + 1; + + for (let numIndex = 1; numIndex < currentLineSize; numIndex += 1) { + // See explanation of this formula in README. + currentLine[numIndex] = currentLine[numIndex - 1] * (lineNumber - numIndex + 1) / numIndex; + } + + return currentLine; +} diff --git a/src/algorithms/math/pascal-triangle/pascalTriangleRecursive.js b/src/algorithms/math/pascal-triangle/pascalTriangleRecursive.js index 4e9d4dc8..120fe251 100644 --- a/src/algorithms/math/pascal-triangle/pascalTriangleRecursive.js +++ b/src/algorithms/math/pascal-triangle/pascalTriangleRecursive.js @@ -1,5 +1,5 @@ /** - * @param {number} lineNumber + * @param {number} lineNumber - zero based. * @return {number[]} */ export default function pascalTriangleRecursive(lineNumber) { diff --git a/src/algorithms/sets/combinations/__test__/combineWithoutRepetitions.test.js b/src/algorithms/sets/combinations/__test__/combineWithoutRepetitions.test.js index 186e9a73..d35e00f3 100644 --- a/src/algorithms/sets/combinations/__test__/combineWithoutRepetitions.test.js +++ b/src/algorithms/sets/combinations/__test__/combineWithoutRepetitions.test.js @@ -1,5 +1,6 @@ import combineWithoutRepetitions from '../combineWithoutRepetitions'; import factorial from '../../../math/factorial/factorial'; +import pascalTriangle from '../../../math/pascal-triangle/pascalTriangle'; describe('combineWithoutRepetitions', () => { it('should combine string without repetitions', () => { @@ -56,5 +57,8 @@ describe('combineWithoutRepetitions', () => { const expectedNumberOfCombinations = factorial(n) / (factorial(r) * factorial(n - r)); expect(combinations.length).toBe(expectedNumberOfCombinations); + + // This one is just to see one of the way of Pascal's triangle application. + expect(combinations.length).toBe(pascalTriangle(n)[r]); }); });