From ce00e13f64eb452040fd76a1537af4f5a4e7cda5 Mon Sep 17 00:00:00 2001 From: Hridyanshu7 Date: Thu, 10 Oct 2024 19:26:12 +0530 Subject: [PATCH 1/5] fix: optimized AverageMean.js by removing redundant comments and unnecessary operations. --- Recursive/SubsetSum.js | 59 ++++++++++++++++++++++++++++ Recursive/test/SubsetSum.test.js | 67 ++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 Recursive/SubsetSum.js create mode 100644 Recursive/test/SubsetSum.test.js diff --git a/Recursive/SubsetSum.js b/Recursive/SubsetSum.js new file mode 100644 index 0000000000..fff41d42b9 --- /dev/null +++ b/Recursive/SubsetSum.js @@ -0,0 +1,59 @@ +/* + * Problem Statement: Given an array of numbers and a target sum, find the number of distinct subsets that sums up to the target. + * + * What is a subset? + * A subset is a selection of elements from an array where the order of elements remains unchanged. A subset can include any combination of elements, including no elements at all (i.e., the empty set). + * Example: Given an array = [1, 2] + * 1. [] is a subset (empty set) + * 2. [1] is a subset + * 3. [2] is a subset + * 4. [1, 2] is a subset + * + * How does the number of subsets relate to the array size? + * An array of size k has 2^k possible subsets. + * Example: For an array = [10, 5], the possible subsets are [], [10], [5], [10, 5]. + * + * Problem Example: + * 1. I/P: arr = [10, 5, 2, 3, 6], sum = 8 + * O/P: 2 (The subsets [2, 6] and [5, 3] both sum to 8) + * + * 2. I/P: arr = [-1, -1, -1], sum = -3 + * O/P: 1 (The subset [-1, -1, -1] sums to -3) + * + * 3. I/P: arr = [40, 9, 77], sum = 3 + * O/P: 0 (No subset sums to 3) + * + * Algorithm: + * Recursively explore all subsets, either including or excluding each element of the array, here inclusion means subtracting the sum by the element included, finally check if sum equals zero, this would indicate that the sum of all the elements included is equal to the target sum. + * + */ + +/** + * @function subsetSum + * @description This function recursively calculates the count of subsets whose sum equals the given target sum. + * @param {number[]} arr - The input array of numbers. + * @param {number} sum - The target sum we want to find in the subsets. + * @param {number} ind - The current index. + * @return {number} The count of subsets whose sum equals the target sum. + * + */ + +export function subsetSum(arr, sum, ind = 0) { + //input validation only in the inital call + if ( + ind === 0 && + (!Array.isArray(arr) || !arr.every((elem) => typeof elem === 'number')) + ) { + throw new TypeError('arr should be an array of numbers') + } + + if (ind === 0 && typeof sum !== 'number') { + throw new TypeError('sum should be a number') + } + + if (ind === arr.length) { + return sum === 0 ? 1 : 0 + } + + return subsetSum(arr, sum, ind + 1) + subsetSum(arr, sum - arr[ind], ind + 1) +} diff --git a/Recursive/test/SubsetSum.test.js b/Recursive/test/SubsetSum.test.js new file mode 100644 index 0000000000..f12d09106b --- /dev/null +++ b/Recursive/test/SubsetSum.test.js @@ -0,0 +1,67 @@ +import { subsetSum } from '../SubsetSum' + +const tests = [ + { + test: { + arr: [10, 5, 2, 3, 6], + sum: 8 + }, + expectedValue: 2 + }, + { + test: { + arr: [-1, -1, -1], + sum: -3 + }, + expectedValue: 1 + }, + { + test: { + arr: [40, 9, 77], + sum: 3 + }, + expectedValue: 0 + } +] + +describe('SubsetSum', () => { + test.each(tests)( + 'should return $expectedValue when input is $test.arr and sum is $test.sum', + ({ test, expectedValue }) => { + expect(subsetSum(test.arr, test.sum)).toBe(expectedValue) + } + ) + + //Empty array cases + it('should return 1 when input is an empty array and sum is 0', () => { + const result = subsetSum([], 0) + expect(result).toBe(1) // Empty subset ([]) sums to 0 + }) + + it('should return 0 when input is an empty array and sum is not 0', () => { + const result = subsetSum([], 5) + expect(result).toBe(0) // No subsets available to sum to 5 + }) + + // Test invalid cases for errors + describe('Invalid input cases', () => { + it('should throw a TypeError when arr is not an array', () => { + expect(() => subsetSum('invalid array', 5)).toThrow(TypeError) + }) + + it('should throw a TypeError when arr contains non-number elements', () => { + expect(() => subsetSum([1, 2, 'three', 4], 5)).toThrow(TypeError) + }) + + it('should throw a TypeError when sum is not a number', () => { + expect(() => subsetSum([1, 2, 3], 'five')).toThrow(TypeError) + }) + }) + + // Edge case + it('should handle large arrays correctly', () => { + const largeArray = Array.from({ length: 20 }, (_, i) => i + 1) // [1, 2, ..., 20] + const result = subsetSum(largeArray, 10) + expect(result).toBeGreaterThan(0) // Ensure this works for large inputs + }) +}) From 54266827ec3b68aa6cded0ba0c54bbc15ded1e1c Mon Sep 17 00:00:00 2001 From: Hridyanshu7 Date: Thu, 17 Oct 2024 18:55:11 +0530 Subject: [PATCH 2/5] fixed spelling mistake --- Recursive/SubsetSum.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Recursive/SubsetSum.js b/Recursive/SubsetSum.js index fff41d42b9..ffb7bbab9c 100644 --- a/Recursive/SubsetSum.js +++ b/Recursive/SubsetSum.js @@ -26,6 +26,7 @@ * Algorithm: * Recursively explore all subsets, either including or excluding each element of the array, here inclusion means subtracting the sum by the element included, finally check if sum equals zero, this would indicate that the sum of all the elements included is equal to the target sum. * + * @see [Subset Sum Problem](https://en.wikipedia.org/wiki/Subset_sum_problem) */ /** @@ -36,10 +37,11 @@ * @param {number} ind - The current index. * @return {number} The count of subsets whose sum equals the target sum. * + * @throws {TypeError} If the input `arr` is not an array of numbers or if the `sum` is not a number. */ export function subsetSum(arr, sum, ind = 0) { - //input validation only in the inital call + //input validation only in the initial call if ( ind === 0 && (!Array.isArray(arr) || !arr.every((elem) => typeof elem === 'number')) From cb9cd5569b47e800e864deb20cbaed2600b92834 Mon Sep 17 00:00:00 2001 From: Hridyanshu7 Date: Wed, 23 Oct 2024 16:56:42 +0530 Subject: [PATCH 3/5] feat: tests added for decimalIsolate and improved comments for clarity --- Maths/DecimalIsolate.js | 11 +++++--- Maths/test/DecimalIsolate.test.js | 45 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Maths/test/DecimalIsolate.test.js diff --git a/Maths/DecimalIsolate.js b/Maths/DecimalIsolate.js index ac9f81a076..63af16801a 100644 --- a/Maths/DecimalIsolate.js +++ b/Maths/DecimalIsolate.js @@ -1,7 +1,12 @@ /* - * function isolates the decimal part of a number. - * Take the number and subtract it from the floored number. - * Return the result. + * This function isolates the decimal part of a number. + * - If input is a number or a numeric string, it isolates and returns the decimal part. + * - If input is an array: + * - It isolates the decimal part of the first element. + * - If the array contains more than one element, only the first element is considered. + * - If the array is empty, it returns 0. + * - If input is not a number, a numeric string, or a valid first element array, + * the function returns 0. */ export const decimalIsolate = (number) => { diff --git a/Maths/test/DecimalIsolate.test.js b/Maths/test/DecimalIsolate.test.js new file mode 100644 index 0000000000..a694d94711 --- /dev/null +++ b/Maths/test/DecimalIsolate.test.js @@ -0,0 +1,45 @@ +import { describe } from 'node:test' +import { decimalIsolate } from '../decimalIsolate' + +const invalidInputs = [ + { input: NaN, description: 'NaN' }, + { input: null, description: 'null' }, + { input: undefined, description: 'undefined' }, + { input: 'a string', description: 'a string' }, + { input: { a: 54.34 }, description: 'an object' }, + { + input: ['OneDotTwoThree', 4.56, 7.89], + description: 'an array with invalid first element' + } +] + +describe('DecimalIsolate', () => { + it('should isolate the decimal part of a positive number', () => { + expect(decimalIsolate(12.34)).toBe(0.34) + }) + + it('should isolate the decimal part of a negative number', () => { + expect(decimalIsolate(-456.789)).toBe(0.789) + }) + + it('should return 0 when the number is a whole number', () => { + expect(decimalIsolate(100)).toBe(0) + }) + + it('should isolate the decimal part of a number string', () => { + expect(decimalIsolate('12.34')).toBe(0.34) + }) + + it('should isolate the decimal part of the first element of an array if it is convertible to a number', () => { + expect(decimalIsolate([98.76, { a: 76.45 }])).toBe(0.76) + }) + + describe('Invalid Inputs', () => { + it.each(invalidInputs)( + 'should return 0 for invalid input when input is $description', + ({ input }) => { + expect(decimalIsolate(input)).toBe(0) + } + ) + }) +}) From 6297d036c846d44a9b00bdaef6bb841d52717967 Mon Sep 17 00:00:00 2001 From: Hridyanshu7 Date: Wed, 23 Oct 2024 17:18:57 +0530 Subject: [PATCH 4/5] fixed wrong import --- Maths/test/DecimalIsolate.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maths/test/DecimalIsolate.test.js b/Maths/test/DecimalIsolate.test.js index a694d94711..fe08ddd284 100644 --- a/Maths/test/DecimalIsolate.test.js +++ b/Maths/test/DecimalIsolate.test.js @@ -1,5 +1,5 @@ import { describe } from 'node:test' -import { decimalIsolate } from '../decimalIsolate' +import { decimalIsolate } from '../DecimalIsolate' const invalidInputs = [ { input: NaN, description: 'NaN' }, From 73b2a5e4514da3ffce1b0f80c8c131df09da986b Mon Sep 17 00:00:00 2001 From: Hridyanshu7 Date: Wed, 23 Oct 2024 17:26:09 +0530 Subject: [PATCH 5/5] removed unnecessary node:test import --- Maths/test/DecimalIsolate.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Maths/test/DecimalIsolate.test.js b/Maths/test/DecimalIsolate.test.js index fe08ddd284..4c021b5d53 100644 --- a/Maths/test/DecimalIsolate.test.js +++ b/Maths/test/DecimalIsolate.test.js @@ -1,4 +1,3 @@ -import { describe } from 'node:test' import { decimalIsolate } from '../DecimalIsolate' const invalidInputs = [