diff --git a/Maths/MotzkinNumber.js b/Maths/MotzkinNumber.js new file mode 100644 index 0000000000..4a751e29e5 --- /dev/null +++ b/Maths/MotzkinNumber.js @@ -0,0 +1,29 @@ +/** + * @function motzkinNumber + * @description Motzkin numbers count the number of different ways of + * drawing non-intersecting chords between points on a circle. + * Sequence: 1, 1, 2, 4, 9, 21, 51, 127, 323, 835... + * @param {number} n - The position in the Motzkin sequence (0-indexed) + * @returns {number} - The nth Motzkin number + * @see https://en.wikipedia.org/wiki/Motzkin_number + * @example motzkinNumber(0) => 1 + * @example motzkinNumber(4) => 9 + * @example motzkinNumber(6) => 51 + */ +const motzkinNumber = (n) => { + if (!Number.isInteger(n) || n < 0) { + throw new TypeError('Input must be a non-negative integer') + } + if (n === 0 || n === 1) return 1 + const dp = new Array(n + 1).fill(0) + dp[0] = 1 + dp[1] = 1 + for (let i = 2; i <= n; i++) { + dp[i] = Math.floor( + ((2 * i + 1) * dp[i - 1] + (3 * i - 3) * dp[i - 2]) / (i + 2) + ) + } + return dp[n] +} + +export { motzkinNumber } diff --git a/Maths/test/MotzkinNumber.test.js b/Maths/test/MotzkinNumber.test.js new file mode 100644 index 0000000000..7aaf5d7fd7 --- /dev/null +++ b/Maths/test/MotzkinNumber.test.js @@ -0,0 +1,47 @@ +import { motzkinNumber } from '../MotzkinNumber.js' + +describe('motzkinNumber', () => { + test('motzkinNumber(0) returns 1', () => { + expect(motzkinNumber(0)).toBe(1) + }) + + test('motzkinNumber(1) returns 1', () => { + expect(motzkinNumber(1)).toBe(1) + }) + + test('motzkinNumber(2) returns 2', () => { + expect(motzkinNumber(2)).toBe(2) + }) + + test('motzkinNumber(3) returns 4', () => { + expect(motzkinNumber(3)).toBe(4) + }) + + test('motzkinNumber(4) returns 9', () => { + expect(motzkinNumber(4)).toBe(9) + }) + + test('motzkinNumber(5) returns 21', () => { + expect(motzkinNumber(5)).toBe(21) + }) + + test('motzkinNumber(6) returns 51', () => { + expect(motzkinNumber(6)).toBe(51) + }) + + test('motzkinNumber(7) returns 127', () => { + expect(motzkinNumber(7)).toBe(127) + }) + + test('motzkinNumber(8) returns 323', () => { + expect(motzkinNumber(8)).toBe(323) + }) + + test('throws TypeError for negative input', () => { + expect(() => motzkinNumber(-1)).toThrow(TypeError) + }) + + test('throws TypeError for float input', () => { + expect(() => motzkinNumber(1.5)).toThrow(TypeError) + }) +})