| 8 | 8 | * @returns {Triplet[]} |
| 9 | 9 | */ |
| 10 | 10 | export function triplets({ minFactor, maxFactor, sum }) { |
| 11 | | throw new Error('Remove this line and implement the function'); |
| 11 | const results = []; |
| 12 | |
| 13 | // Edge Case: Invalid input parameters where minFactor > maxFactor |
| 14 | if (minFactor > maxFactor) { |
| 15 | return results; |
| 16 | } |
| 17 | |
| 18 | // Edge Case: Sum is too small to form a valid triplet |
| 19 | if (sum < 3) { |
| 20 | return results; |
| 21 | } |
| 22 | |
| 23 | // Using Euclid's formula for generating Pythagorean triplets |
| 24 | // For integers m > n > 0: |
| 25 | // a = m² - n² |
| 26 | // b = 2mn |
| 27 | // c = m² + n² |
| 28 | |
| 29 | // We need a + b + c = sum |
| 30 | // (m² - n²) + 2mn + (m² + n²) = sum |
| 31 | // 2m² + 2mn = sum |
| 32 | // 2m(m + n) = sum |
| 33 | // m(m + n) = sum/2 |
| 34 | |
| 35 | // Edge Case: Sum must be even to have integer solutions |
| 36 | if (sum % 2 !== 0) { |
| 37 | return results; |
| 38 | } |
| 39 | |
| 40 | const halfSum = sum / 2; |
| 41 | |
| 42 | // Find all possible values of m |
| 43 | for (let m = 2; m * m < halfSum; m++) { |
| 44 | // Edge Case: m must divide halfSum |
| 45 | if (halfSum % m === 0) { |
| 46 | const n = halfSum / m - m; |
| 47 | |
| 48 | // Edge Case: n must be positive and less than m |
| 49 | if (n > 0 && n < m) { |
| 50 | // Generate the triplet |
| 51 | const a = m * m - n * n; |
| 52 | const b = 2 * m * n; |
| 53 | const c = m * m + n * n; |
| 54 | |
| 55 | // Edge Case: Ensure a < b (since we need a < b < c) |
| 56 | const [sortedA, sortedB] = a < b ? [a, b] : [b, a]; |
| 57 | |
| 58 | // Edge Case: Check if the factors are within the specified range |
| 59 | if (sortedA >= minFactor && sortedA <= maxFactor && |
| 60 | sortedB >= minFactor && sortedB <= maxFactor && |
| 61 | c >= minFactor && c <= maxFactor) { |
| 62 | results.push(new Triplet(sortedA, sortedB, c)); |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // Edge Case: Handle primitive triplets and their multiples |
| 69 | // The above approach only finds primitive triplets, we need to check multiples too |
| 70 | const directSearchResults = []; |
| 71 | |
| 72 | // Direct search approach for completeness |
| 73 | for (let a = minFactor; a <= Math.min(maxFactor, Math.floor((sum - 3) / 3)); a++) { |
| 74 | // Using the constraint a + b + c = sum and a² + b² = c² |
| 75 | // We can derive: b = (sum² - 2*sum*a) / (2*(sum-a)) |
| 76 | |
| 77 | // Edge Case: Avoid division by zero |
| 78 | if (2 * (sum - a) === 0) continue; |
| 79 | |
| 80 | const numerator = sum * sum - 2 * sum * a; |
| 81 | const denominator = 2 * (sum - a); |
| 82 | |
| 83 | // Edge Case: b must be an integer |
| 84 | if (numerator % denominator !== 0) continue; |
| 85 | |
| 86 | const b = numerator / denominator; |
| 87 | const c = sum - a - b; |
| 88 | |
| 89 | // Edge Case: Check ordering a < b < c |
| 90 | if (a < b && b < c) { |
| 91 | // Edge Case: Check if b and c are within range |
| 92 | if (b >= minFactor && b <= maxFactor && c >= minFactor && c <= maxFactor) { |
| 93 | // Edge Case: Verify it's actually a Pythagorean triplet |
| 94 | if (a * a + b * b === c * c) { |
| 95 | directSearchResults.push(new Triplet(a, b, c)); |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | // Combine results and remove duplicates |
| 102 | const allResults = [...results, ...directSearchResults]; |
| 103 | const uniqueResults = []; |
| 104 | const seen = new Set(); |
| 105 | |
| 106 | for (const triplet of allResults) { |
| 107 | const [a, b, c] = triplet.toArray(); |
| 108 | const key = `${a},${b},${c}`; |
| 109 | |
| 110 | // Edge Case: Avoid duplicate triplets |
| 111 | if (!seen.has(key)) { |
| 112 | seen.add(key); |
| 113 | uniqueResults.push(triplet); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | return uniqueResults; |
| 118 | // Handled Edge Cases: Invalid input parameters where minFactor > maxFactor, Sum is too small to form a valid triplet, Sum must be even to have integer solutions, m must divide halfSum, n must be positive and less than m, Ensure a < b (since we need a < b < c), Check if the factors are within the specified range, Avoid division by zero, b must be an integer, Check ordering a < b < c, Check if b and c are within range, Verify it's actually a Pythagorean triplet, Avoid duplicate triplets |
| 12 | 119 | } |
| 13 | 120 | |
| 14 | 121 | class Triplet { |
| 18 | 125 | * @param {number} c |
| 19 | 126 | */ |
| 20 | 127 | constructor(a, b, c) { |
| 21 | | throw new Error('Remove this line and implement the function'); |
| 128 | // Edge Case: Validate that inputs are positive integers |
| 129 | if (!Number.isInteger(a) || !Number.isInteger(b) || !Number.isInteger(c) || a <= 0 || b <= 0 || c <= 0) { |
| 130 | throw new Error('Triplet values must be positive integers'); |
| 131 | } |
| 132 | |
| 133 | // Edge Case: Validate Pythagorean condition |
| 134 | if (a * a + b * b !== c * c) { |
| 135 | throw new Error('Values do not form a Pythagorean triplet'); |
| 136 | } |
| 137 | |
| 138 | // Edge Case: Validate ordering |
| 139 | if (!(a < b && b < c)) { |
| 140 | throw new Error('Values must be in ascending order'); |
| 141 | } |
| 142 | |
| 143 | this.a = a; |
| 144 | this.b = b; |
| 145 | this.c = c; |
| 146 | // Handled Edge Cases: Validate that inputs are positive integers, Validate Pythagorean condition, Validate ordering |
| 22 | 147 | } |
| 23 | 148 | |
| 24 | 149 | /** |
| 25 | 150 | * @returns {number[]} |
| 26 | 151 | */ |
| 27 | 152 | toArray() { |
| 28 | | throw new Error('Remove this line and implement the function'); |
| 153 | return [this.a, this.b, this.c]; |
| 154 | // Handled Edge Cases: None |
| 29 | 155 | } |
| 30 | 156 | } |