diff --git a/.github/workflows/Ci.yml b/.github/workflows/Ci.yml index 99e8f7831f..ee55d797d6 100644 --- a/.github/workflows/Ci.yml +++ b/.github/workflows/Ci.yml @@ -36,4 +36,4 @@ jobs: with: # file types to ignore skip: "*.json,*.yml,DIRECTORY.md" - ignore_words_list: "ba,esy,yse,falsy" + ignore_words_list: "ba,esy,yse,falsy,abd" diff --git a/.gitignore b/.gitignore index 1cc076e7bb..78aa317e3e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,7 @@ yarn-error.log* # intelliJ workspace folder .idea +.vscode +.trae /coverage diff --git a/Ciphers/KeyFinder.js b/Ciphers/KeyFinder.js index 64a3d1c9d4..0b799e7496 100644 --- a/Ciphers/KeyFinder.js +++ b/Ciphers/KeyFinder.js @@ -52,7 +52,7 @@ function keyFinder(str) { return k // return the key number if founded } outStrElement = '' // reset the temp word - } // end for ( let i=0; i < wordBank.length; i++) + } // end for (let i=0; i < wordBank.length; i++) } } return 0 // return 0 if found nothing diff --git a/DIRECTORY.md b/DIRECTORY.md index 5e8e1f401a..b7b8aca45d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -69,7 +69,7 @@ * [UpperCaseConversion](Conversions/UpperCaseConversion.js) * **Data-Structures** * **Array** - * [LocalMaximomPoint](Data-Structures/Array/LocalMaximomPoint.js) + * [LocalMaximumPoint](Data-Structures/Array/LocalMaximumPoint.js) * [NumberOfLocalMaximumPoints](Data-Structures/Array/NumberOfLocalMaximumPoints.js) * [QuickSelect](Data-Structures/Array/QuickSelect.js) * [Reverse](Data-Structures/Array/Reverse.js) @@ -321,6 +321,9 @@ * [StringSearch](Search/StringSearch.js) * [TernarySearch](Search/TernarySearch.js) * [UnionFind](Search/UnionFind.js) +* **Sliding-Windows** + * [MaxSumSubarrayFixed](Sliding-Windows/MaxSumSubarrayFixed.js) + * [LongestSubarrayWithSumAtMost](Sliding-Windows/LongestSubarrayWithSumAtMost.js) * **Sorts** * [AlphaNumericalSort](Sorts/AlphaNumericalSort.js) * [BeadSort](Sorts/BeadSort.js) diff --git a/Data-Structures/Array/LocalMaximomPoint.js b/Data-Structures/Array/LocalMaximumPoint.js similarity index 93% rename from Data-Structures/Array/LocalMaximomPoint.js rename to Data-Structures/Array/LocalMaximumPoint.js index f971c62814..fc6dbd3f0b 100644 --- a/Data-Structures/Array/LocalMaximomPoint.js +++ b/Data-Structures/Array/LocalMaximumPoint.js @@ -44,6 +44,6 @@ const findMaxPointIndex = ( } } -const LocalMaximomPoint = (A) => findMaxPointIndex(A, 0, A.length - 1, A.length) +const LocalMaximumPoint = (A) => findMaxPointIndex(A, 0, A.length - 1, A.length) -export { LocalMaximomPoint } +export { LocalMaximumPoint } diff --git a/Data-Structures/Array/test/LocalMaximomPoint.test.js b/Data-Structures/Array/test/LocalMaximumPoint.test.js similarity index 64% rename from Data-Structures/Array/test/LocalMaximomPoint.test.js rename to Data-Structures/Array/test/LocalMaximumPoint.test.js index db7d911949..5e7d6a0afe 100644 --- a/Data-Structures/Array/test/LocalMaximomPoint.test.js +++ b/Data-Structures/Array/test/LocalMaximumPoint.test.js @@ -1,29 +1,29 @@ -import { LocalMaximomPoint } from '../LocalMaximomPoint' +import { LocalMaximumPoint } from '../LocalMaximumPoint' describe('LocalMaximumPoint tests', () => { it('test boundary maximum points - last element', () => { const Array = [1, 2, 3, 4, 5, 6, 12] - expect(LocalMaximomPoint(Array)).toEqual(6) + expect(LocalMaximumPoint(Array)).toEqual(6) }) it('test boundary maximum points - first element', () => { const Array2 = [13, 6, 5, 4, 3, 2, 1] - expect(LocalMaximomPoint(Array2)).toEqual(0) + expect(LocalMaximumPoint(Array2)).toEqual(0) }) - it('test boundary maximum points - should find first maximom point from the top', () => { + it('test boundary maximum points - should find first maximum point from the top', () => { // Test a mix of number types (i.e., positive/negative, numbers with decimals, fractions) const Array = [13, 2, 3, 4, 5, 6, 12] - expect(LocalMaximomPoint(Array)).toEqual(6) + expect(LocalMaximumPoint(Array)).toEqual(6) }) it('test inner points - second element', () => { const Array2 = [13, 16, 5, 4, 3, 2, 1] - expect(LocalMaximomPoint(Array2)).toEqual(1) + expect(LocalMaximumPoint(Array2)).toEqual(1) }) it('test inner points - element some where in the middle', () => { const Array2 = [13, 16, 5, 41, 3, 2, 1] - expect(LocalMaximomPoint(Array2)).toEqual(3) + expect(LocalMaximumPoint(Array2)).toEqual(3) }) }) diff --git a/Data-Structures/Array/test/NumberOfLocalMaximumPoints.test.js b/Data-Structures/Array/test/NumberOfLocalMaximumPoints.test.js index 41e7b04b52..6e6d116b82 100644 --- a/Data-Structures/Array/test/NumberOfLocalMaximumPoints.test.js +++ b/Data-Structures/Array/test/NumberOfLocalMaximumPoints.test.js @@ -1,6 +1,6 @@ import { NumberOfLocalMaximumPoints } from '../NumberOfLocalMaximumPoints' -describe('LocalMaximomPoint tests', () => { +describe('LocalMaximumPoint tests', () => { it('test boundary maximum points - last element', () => { const Array = [1, 2, 3, 4, 5, 6, 12] expect(NumberOfLocalMaximumPoints(Array)).toEqual(1) diff --git a/Data-Structures/Tree/SegmentTree.js b/Data-Structures/Tree/SegmentTree.js index 3d27981a07..c33b455dcd 100644 --- a/Data-Structures/Tree/SegmentTree.js +++ b/Data-Structures/Tree/SegmentTree.js @@ -64,7 +64,7 @@ class SegmentTree { } } - // interval [L,R) with left index(L) included and right (R) excluded. + // interval [L, R) with left index(L) included and right (R) excluded. query(left, right) { const { size, tree } = this // cause R is excluded, increase right for convenient diff --git a/Dynamic-Programming/UniquePaths.js b/Dynamic-Programming/UniquePaths.js index a37049b2f4..8588ef510f 100644 --- a/Dynamic-Programming/UniquePaths.js +++ b/Dynamic-Programming/UniquePaths.js @@ -30,7 +30,7 @@ const uniquePaths = (m, n) => { for (let j = 1; j < m; j++) { // paths[j] in RHS represents the cell value stored above the current cell // paths[j-1] in RHS represents the cell value stored to the left of the current cell - // paths [j] on the LHS represents the number of distinct pathways to the cell (i,j) + // paths [j] on the LHS represents the number of distinct pathways to the cell (i, j) paths[j] = paths[j - 1] + paths[j] } } diff --git a/Geometry/ConvexHullGraham.js b/Geometry/ConvexHullGraham.js index 0d400242dd..6cdae1de7b 100644 --- a/Geometry/ConvexHullGraham.js +++ b/Geometry/ConvexHullGraham.js @@ -13,7 +13,7 @@ function compare(a, b) { return 1 } function orientation(a, b, c) { - // Check orientation of Line(a,b) and Line(b,c) + // Check orientation of Line(a, b) and Line(b, c) const alpha = (b.y - a.y) / (b.x - a.x) const beta = (c.y - b.y) / (c.x - b.x) diff --git a/Graphs/Dijkstra.js b/Graphs/Dijkstra.js index a836df0ff1..165a2c4d35 100644 --- a/Graphs/Dijkstra.js +++ b/Graphs/Dijkstra.js @@ -8,7 +8,7 @@ function createGraph(V, E) { // V - Number of vertices in graph - // E - Number of edges in graph (u,v,w) + // E - Number of edges in graph (u, v, w) const adjList = [] // Adjacency list for (let i = 0; i < V; i++) { adjList.push([]) diff --git a/Maths/Abs.js b/Maths/Abs.js index 53c353fb8b..d74174d731 100644 --- a/Maths/Abs.js +++ b/Maths/Abs.js @@ -16,7 +16,7 @@ const abs = (num) => { throw new TypeError('Argument is NaN - Not a Number') } - return validNumber < 0 ? -validNumber : validNumber // if number is less than zero mean negative then it converted to positive. i.e -> n = -2 = -(-2) = 2 + return validNumber < 0 ? -validNumber : validNumber // if number is less than zero means negative, then it converted to positive. i.e., n = -2 = -(-2) = 2 } export { abs } diff --git a/Maths/AverageMean.js b/Maths/AverageMean.js index 8ae3b55992..3df7b2769b 100644 --- a/Maths/AverageMean.js +++ b/Maths/AverageMean.js @@ -1,19 +1,30 @@ /** * @function mean * @description This script will find the mean value of a array of numbers. - * @param {Integer[]} nums - Array of integer - * @return {Integer} - mean of nums. + * @param {number[]} numbers - Array of integer + * @return {number} - mean of numbers. + * @throws {TypeError} If the input is not an array or contains non-number elements. + * @throws {Error} If the input array is empty. * @see [Mean](https://en.wikipedia.org/wiki/Mean) * @example mean([1, 2, 4, 5]) = 3 * @example mean([10, 40, 100, 20]) = 42.5 */ - -const mean = (nums) => { - if (!Array.isArray(nums)) { +const mean = (numbers) => { + if (!Array.isArray(numbers)) { throw new TypeError('Invalid Input') + } else if (numbers.length === 0) { + throw new Error('Array is empty') } - return nums.reduce((sum, cur) => sum + cur, 0) / nums.length + let total = 0 + numbers.forEach((num) => { + if (typeof num !== 'number') { + throw new TypeError('Invalid Input') + } + total += num + }) + + return total / numbers.length } export { mean } diff --git a/Maths/BinaryExponentiationIterative.js b/Maths/BinaryExponentiationIterative.js index 9c1a23f215..e53617e305 100644 --- a/Maths/BinaryExponentiationIterative.js +++ b/Maths/BinaryExponentiationIterative.js @@ -1,4 +1,4 @@ -// To calculate x^n i.e. exponent(x, n) in O(log n) time in iterative way +// To calculate x^n i.e., exponent(x, n) in O(log n) time in iterative way // n is an integer and n >= 0 // Explanation: https://en.wikipedia.org/wiki/Exponentiation_by_squaring diff --git a/Maths/EulersTotient.js b/Maths/EulersTotient.js index 09d05377af..608b008c1d 100644 --- a/Maths/EulersTotient.js +++ b/Maths/EulersTotient.js @@ -17,7 +17,7 @@ export const EulersTotient = (n) => { while (n % i === 0) { n = Math.floor(n / i) } - // i is a prime diving n, multiply res by 1 - 1/i + // i is a prime dividing n, multiply res by 1 - 1/i // res = res * (1 - 1/i) = res - (res / i) res = res - Math.floor(res / i) } diff --git a/Maths/EulersTotientFunction.js b/Maths/EulersTotientFunction.js index 387a93fa2b..2c1d0fd82c 100644 --- a/Maths/EulersTotientFunction.js +++ b/Maths/EulersTotientFunction.js @@ -13,7 +13,7 @@ const gcdOfTwoNumbers = (x, y) => { // let gcd of x and y is gcdXY // so it divides x and y completely // so gcdXY should also divide y%x (y = gcdXY*a and x = gcdXY*b and y%x = y - x*k so y%x = gcdXY(a - b*k)) - // and gcd(x,y) is equal to gcd(y%x , x) + // and gcd(x,y) is equal to gcd(y%x, x) return x === 0 ? y : gcdOfTwoNumbers(y % x, x) } diff --git a/Maths/MatrixMultiplication.js b/Maths/MatrixMultiplication.js index b6626d0190..19324adca1 100644 --- a/Maths/MatrixMultiplication.js +++ b/Maths/MatrixMultiplication.js @@ -17,7 +17,7 @@ const matrixCheck = (matrix) => { } } -// tests to see if the matrices have a like side, i.e. the row length on the first matrix matches the column length on the second matrix, or vice versa. +// tests to see if the matrices have a like side, i.e., the row length on the first matrix matches the column length on the second matrix, or vice versa. const twoMatricesCheck = (first, second) => { const [firstRowLength, secondRowLength, firstColLength, secondColLength] = [ first.length, diff --git a/Maths/Polynomial.js b/Maths/Polynomial.js index 00f96761c6..caec53c34f 100644 --- a/Maths/Polynomial.js +++ b/Maths/Polynomial.js @@ -11,7 +11,7 @@ class Polynomial { constructor(array) { this.coefficientArray = array // array of coefficients - this.polynomial = '' // in terms of x e.g. (2x) + (1) + this.polynomial = '' // in terms of x e.g., (2x) + (1) this.construct() } diff --git a/Maths/test/AverageMean.test.js b/Maths/test/AverageMean.test.js index 7d0bd3a6ac..ce9109b916 100644 --- a/Maths/test/AverageMean.test.js +++ b/Maths/test/AverageMean.test.js @@ -18,4 +18,50 @@ describe('Tests for average mean', () => { const meanFunction = mean([10, 40, 100, 20]) expect(meanFunction).toBe(42.5) }) + + it('should return the number itself for a single-element array', () => { + const result = mean([5]) + expect(result).toBe(5) + }) + + it('should throw error for empty array', () => { + expect(() => mean([])).toThrow() + }) + + it('should throw error for an array containing null', () => { + expect(() => mean([1, 2, null])).toThrow() + }) + + it('should throw error for an array containing booleans', () => { + expect(() => mean([1, 2, true])).toThrow() + }) + + it('should throw error for an array containing strings', () => { + expect(() => mean([1, 2, 'asd'])).toThrow() + }) + + it('should return the mean of an array with negative numbers', () => { + const result = mean([-1, -2, -3, -4]) + expect(result).toBe(-2.5) + }) + + it('should return the mean of an array with floating-point numbers', () => { + const result = mean([1.5, 2.5, 3.5]) + expect(result).toBe(2.5) + }) + + it('should return 0 for an array with zeros', () => { + const result = mean([0, 0, 0]) + expect(result).toBe(0) + }) + + it('should handle very large numbers correctly', () => { + const result = mean([1000000000, 2000000000, 3000000000]) + expect(result).toBe(2000000000) + }) + + it('should return correct mean for an array with integers and floating-point numbers', () => { + const result = mean([1, 2.5, 3]) + expect(result).toBeCloseTo(2.1667, 4) + }) }) diff --git a/Maths/test/Pow.test.js b/Maths/test/Pow.test.js index 9ffb64e52d..7f3e698e42 100644 --- a/Maths/test/Pow.test.js +++ b/Maths/test/Pow.test.js @@ -36,6 +36,6 @@ describe('Testing powFaster function', () => { }) it('should return the result in O(lonN) complexity', () => { - expect(powFaster(2, 64)).toBe(18446744073709552000) // execution time Math.log2(64) -> 6 + expect(powFaster(2, 64)).toBe(18446744073709552000) // execution time Math. log2(64) -> 6 }) }) diff --git a/Search/UnionFind.js b/Search/UnionFind.js index 5b234da9a1..dd78dcdecb 100644 --- a/Search/UnionFind.js +++ b/Search/UnionFind.js @@ -21,7 +21,7 @@ function UnionFind(n, key) { } let cnt, length // init Union Find with number of distinct groups. Each group will be referred to as index of the array of size 'size' starting at 0. - // Provide an optional key function that maps these indices. I.e. for the groups starting with 1 provide function(a){return a-1;}. The default value is function(a){return a;}. + // Provide an optional key function that maps these indices. I.e., for the groups starting with 1 provide function(a){return a-1;}. The default value is function(a){return a;}. key = key || function (a) { diff --git a/Sliding-Windows/LongestSubarrayWithSumAtMost.js b/Sliding-Windows/LongestSubarrayWithSumAtMost.js new file mode 100644 index 0000000000..b970539ee0 --- /dev/null +++ b/Sliding-Windows/LongestSubarrayWithSumAtMost.js @@ -0,0 +1,21 @@ +/** + * Function to find the longest subarray with a sum <= target. + * + * @param {number[]} arr - The input array of numbers. + * @param {number} target - The target sum for the dynamic window. + * @returns {number} - The length of the longest subarray with a sum <= target. + */ +export function longestSubarrayWithSumAtMost(arr, target) { + let maxLength = 0 + let windowSum = 0 + let left = 0 + for (let right = 0; right < arr.length; right++) { + windowSum += arr[right] + while (windowSum > target) { + windowSum -= arr[left] + left++ + } + maxLength = Math.max(maxLength, right - left + 1) + } + return maxLength +} diff --git a/Sliding-Windows/MaxSumSubarrayFixed.js b/Sliding-Windows/MaxSumSubarrayFixed.js new file mode 100644 index 0000000000..ba8b844f14 --- /dev/null +++ b/Sliding-Windows/MaxSumSubarrayFixed.js @@ -0,0 +1,26 @@ +/** + * Function to find the maximum sum of a subarray of fixed size k. + * + * @param {number[]} arr - The input array of numbers. + * @param {number} k - The fixed size of the subarray. + * @returns {number} - The maximum sum of any subarray of size k. + * @throws {RangeError} - If k is larger than the array length or less than 1. + */ +export function maxSumSubarrayFixed(arr, k) { + if (k > arr.length || k < 1) { + throw new RangeError( + 'Subarray size k must be between 1 and the length of the array' + ) + } + let maxSum = 0 + let windowSum = 0 + for (let i = 0; i < k; i++) { + windowSum += arr[i] + } + maxSum = windowSum + for (let i = k; i < arr.length; i++) { + windowSum += arr[i] - arr[i - k] + maxSum = Math.max(maxSum, windowSum) + } + return maxSum +} diff --git a/Sliding-Windows/test/LongestSubarrayWithSumAtMost.test.js b/Sliding-Windows/test/LongestSubarrayWithSumAtMost.test.js new file mode 100644 index 0000000000..c33188fffb --- /dev/null +++ b/Sliding-Windows/test/LongestSubarrayWithSumAtMost.test.js @@ -0,0 +1,24 @@ +import { longestSubarrayWithSumAtMost } from '../LongestSubarrayWithSumAtMost' + +describe('Dynamic-size Sliding Window - longestSubarrayWithSumAtMost', () => { + it('should return the longest subarray length with sum <= target', () => { + const arr = [1, 2, 3, 4, 5] + const target = 7 + const result = longestSubarrayWithSumAtMost(arr, target) + expect(result).toBe(3) + }) + + it('should return the full array length if the entire sum is within the target', () => { + const arr = [1, 1, 1, 1] + const target = 4 + const result = longestSubarrayWithSumAtMost(arr, target) + expect(result).toBe(4) + }) + + it('should return 0 if no subarray meets the sum condition', () => { + const arr = [5, 6, 7] + const target = 3 + const result = longestSubarrayWithSumAtMost(arr, target) + expect(result).toBe(0) + }) +}) diff --git a/Sliding-Windows/test/MaxSumSubarrayFixed.test.js b/Sliding-Windows/test/MaxSumSubarrayFixed.test.js new file mode 100644 index 0000000000..d4ca107c65 --- /dev/null +++ b/Sliding-Windows/test/MaxSumSubarrayFixed.test.js @@ -0,0 +1,22 @@ +import { maxSumSubarrayFixed } from '../MaxSumSubarrayFixed' + +describe('Fixed-size Sliding Window - maxSumSubarrayFixed', () => { + it('should return the maximum sum of a subarray of size k', () => { + const arr = [2, 1, 5, 1, 3, 2] + const k = 3 + const result = maxSumSubarrayFixed(arr, k) + expect(result).toBe(9) + }) + + it('should throw a RangeError if k is larger than the array length', () => { + const arr = [2, 1, 5] + const k = 4 + expect(() => maxSumSubarrayFixed(arr, k)).toThrow(RangeError) + }) + + it('should throw a RangeError if k is less than 1', () => { + const arr = [2, 1, 5] + const k = 0 + expect(() => maxSumSubarrayFixed(arr, k)).toThrow(RangeError) + }) +}) diff --git a/String/AlphaNumericPalindrome.js b/String/AlphaNumericPalindrome.js index 98976f1d7d..0b1460069a 100644 --- a/String/AlphaNumericPalindrome.js +++ b/String/AlphaNumericPalindrome.js @@ -11,7 +11,7 @@ * like "2A3*3a2", "2A3 3a2", and "2_A3*3#A2" * * But the catch is, we have to check only if the alphanumeric characters - * are palindrome i.e remove spaces, symbols, punctuations etc + * are palindrome i.e remove spaces, symbols, punctuation etc * and the case of the characters doesn't matter */ const alphaNumericPalindrome = (str) => { diff --git a/String/CheckPalindrome.js b/String/CheckPalindrome.js index a717ccd5f4..251e0b192f 100644 --- a/String/CheckPalindrome.js +++ b/String/CheckPalindrome.js @@ -1,4 +1,4 @@ -// Palindrome check is case sensitive; i.e. Aba is not a palindrome +// Palindrome check is case sensitive; i.e., Aba is not a palindrome // input is a string const checkPalindrome = (str) => { // check that input is a string