diff --git a/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js b/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js index ce738c3..0199894 100644 --- a/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js +++ b/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js @@ -9,26 +9,53 @@ * "product": 30 // 2 * 3 * 5 * } * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Time Complexity: O(n) - Single pass through the array + * Space Complexity: O(1) - Only using constant extra space + * Optimal Time Complexity: O(n) - Cannot do better than linear time * * @param {Array} numbers - Numbers to process * @returns {Object} Object containing running total and product */ export function calculateSumAndProduct(numbers) { - let sum = 0; - for (const num of numbers) { - sum += num; - } + // OPTIMIZED IMPLEMENTATION: Single pass algorithm + // Previous implementation used two separate loops (2n operations) + // This version combines both calculations in one loop (n operations) + + let sum = 0; // O(1) space + let product = 1; // O(1) space - let product = 1; + // Single pass through array: O(n) time complexity for (const num of numbers) { - product *= num; + sum += num; // O(1) operation per element + product *= num; // O(1) operation per element } - return { - sum: sum, - product: product, - }; + // Return optimized object syntax: O(1) space + return { sum, product }; } + +/* + * ORIGINAL IMPLEMENTATION (for comparison): + * + * export function calculateSumAndProduct(numbers) { + * let sum = 0; + * for (const num of numbers) { // First pass: O(n) + * sum += num; + * } + * + * let product = 1; + * for (const num of numbers) { // Second pass: O(n) + * product *= num; + * } + * + * return { // Total: O(2n) = O(n) time + * sum: sum, // O(1) space + * product: product, + * }; + * } + * + * IMPROVEMENTS MADE: + * 1. Reduced from 2n to n operations (50% fewer iterations) + * 2. Better cache locality (single pass through memory) + * 3. Same O(n) time complexity but with better constant factors + */ diff --git a/Sprint-1/JavaScript/findCommonItems/findCommonItems.js b/Sprint-1/JavaScript/findCommonItems/findCommonItems.js index 5619ae5..2e9cdd5 100644 --- a/Sprint-1/JavaScript/findCommonItems/findCommonItems.js +++ b/Sprint-1/JavaScript/findCommonItems/findCommonItems.js @@ -1,14 +1,46 @@ /** * Finds common items between two arrays. * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Time Complexity: O(n + m) - Single pass through both arrays + * Space Complexity: O(min(n, m)) - Set size bounded by smaller array + * Optimal Time Complexity: O(n + m) - Cannot do better than linear time * * @param {Array} firstArray - First array to compare * @param {Array} secondArray - Second array to compare * @returns {Array} Array containing unique common items */ -export const findCommonItems = (firstArray, secondArray) => [ - ...new Set(firstArray.filter((item) => secondArray.includes(item))), -]; +export const findCommonItems = (firstArray, secondArray) => { + // OPTIMIZED IMPLEMENTATION: O(n + m) time complexity + // Previous implementation: O(n × m) due to nested includes() calls + + // Convert second array to Set for O(1) lookup: O(m) time, O(m) space + const secondSet = new Set(secondArray); + + // Find common items using Set lookup: O(n) time + const commonItems = firstArray.filter((item) => secondSet.has(item)); + + // Remove duplicates: O(n) time in worst case + return [...new Set(commonItems)]; +}; + +/* + * ORIGINAL IMPLEMENTATION (for comparison): + * + * export const findCommonItems = (firstArray, secondArray) => [ + * ...new Set(firstArray.filter((item) => secondArray.includes(item))), + * ]; + * + * COMPLEXITY ANALYSIS OF ORIGINAL: + * - firstArray.filter(): O(n) iterations + * - secondArray.includes(): O(m) for each iteration + * - Total: O(n × m) time complexity + * - Space: O(n) for Set creation + * + + * IMPROVEMENTS MADE: + * 1. Reduced from O(n × m) to O(n + m) time complexity + * 2. Set lookup is O(1) vs Array.includes() O(m) + * 3. Significant performance gain for large arrays + * 4. Same functionality with better algorithmic efficiency + + */ diff --git a/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js b/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js index dd2901f..50b7c43 100644 --- a/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js +++ b/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js @@ -1,21 +1,59 @@ /** * Find if there is a pair of numbers that sum to a given target value. * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Time Complexity: O(n) - Single pass through the array + * Space Complexity: O(n) - Set to store seen numbers + * Optimal Time Complexity: O(n) - Cannot do better than linear time * * @param {Array} numbers - Array of numbers to search through * @param {number} target - Target sum to find * @returns {boolean} True if pair exists, false otherwise */ export function hasPairWithSum(numbers, target) { - for (let i = 0; i < numbers.length; i++) { - for (let j = i + 1; j < numbers.length; j++) { - if (numbers[i] + numbers[j] === target) { - return true; - } + // OPTIMIZED IMPLEMENTATION: O(n) time complexity + // Previous implementation: O(n²) due to nested loops + + const seen = new Set(); // O(n) + + // O(n) time complexity + for (const num of numbers) { + const complement = target - num; + // O(1) lookup + if (seen.has(complement)) { + return true; } + + // O(1) operation + seen.add(num); } return false; } +console.log(hasPairWithSum([3, 2, 3, 4, 5], 9)); +/* + * ORIGINAL IMPLEMENTATION (for comparison): + * + * export function hasPairWithSum(numbers, target) { + * for (let i = 0; i < numbers.length; i++) { // O(n) iterations + * for (let j = i + 1; j < numbers.length; j++) { // O(n) iterations each + * if (numbers[i] + numbers[j] === target) { // O(1) comparison + * return true; + * } + * } + * } + * return false; + * } + * + * COMPLEXITY ANALYSIS OF ORIGINAL: + * - Outer loop: O(n) iterations + * - Inner loop: O(n) iterations for each outer iteration + * - Total: O(n²) time complexity + * - Space: O(1) - only using loop variables + * + * PERFORMANCE ISSUES: + * - Quadratic time complexity O(n²) + * + * IMPROVEMENTS MADE: + * 1. Reduced from O(n²) to O(n) time complexity + * 2. Single pass through array instead of nested loops + * 3. Set lookup is O(1) vs nested iteration O(n) + */ diff --git a/Sprint-1/JavaScript/package-lock.json b/Sprint-1/JavaScript/package-lock.json new file mode 100644 index 0000000..37ca6f0 --- /dev/null +++ b/Sprint-1/JavaScript/package-lock.json @@ -0,0 +1,12 @@ +{ + "name": "module-complexity-sprint-1", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "module-complexity-sprint-1", + "version": "1.0.0" + } + } +} diff --git a/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs b/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs index dc5f771..3d701cd 100644 --- a/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs +++ b/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs @@ -1,36 +1,65 @@ /** * Remove duplicate values from a sequence, preserving the order of the first occurrence of each value. * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Time Complexity: O(n) - Single pass through the array + * Space Complexity: O(n) - Set to track seen elements + * Optimal Time Complexity: O(n) - Cannot do better than linear time * * @param {Array} inputSequence - Sequence to remove duplicates from * @returns {Array} New sequence with duplicates removed */ export function removeDuplicates(inputSequence) { - const uniqueItems = []; + // OPTIMIZED IMPLEMENTATION: O(n) time complexity + // Previous implementation: O(n²) due to nested loops checking each element - for ( - let currentIndex = 0; - currentIndex < inputSequence.length; - currentIndex++ - ) { - let isDuplicate = false; - for ( - let compareIndex = 0; - compareIndex < uniqueItems.length; - compareIndex++ - ) { - if (inputSequence[currentIndex] === uniqueItems[compareIndex]) { - isDuplicate = true; - break; - } - } - if (!isDuplicate) { - uniqueItems.push(inputSequence[currentIndex]); + const seen = new Set(); // O(n) + const uniqueItems = []; // O(n) + + // O(n) time complexity + for (const item of inputSequence) { + // O(1) lookup + if (!seen.has(item)) { + seen.add(item); // O(1) operation + uniqueItems.push(item); // O(1) operation } } return uniqueItems; } +console.log(removeDuplicates([1, 2, 3, 4, 5, 1, 2, 3, 4, 5])); +/* + * ORIGINAL IMPLEMENTATION (for comparison): + * + * export function removeDuplicates(inputSequence) { + * const uniqueItems = []; + * + * for (let currentIndex = 0; currentIndex < inputSequence.length; currentIndex++) { + * let isDuplicate = false; + * for (let compareIndex = 0; compareIndex < uniqueItems.length; compareIndex++) { + * if (inputSequence[currentIndex] === uniqueItems[compareIndex]) { + * isDuplicate = true; + * break; + * } + * } + * if (!isDuplicate) { + * uniqueItems.push(inputSequence[currentIndex]); + * } + * } + * + * return uniqueItems; + * } + * + * COMPLEXITY ANALYSIS OF ORIGINAL: + * - Outer loop: O(n) iterations through input array + * - Inner loop: O(k) iterations through uniqueItems array (k grows with each unique element) + * - Worst case: O(n²) when all elements are unique + * - Space: O(n) for uniqueItems array + * + * PERFORMANCE ISSUES: + * - Quadratic time complexity O(n²) in worst case + * + * IMPROVEMENTS MADE: + * 1. Reduced from O(n²) to O(n) time complexity + * 2. Set lookup is O(1) vs linear search O(k) + * 3. Single pass through input array + */ diff --git a/Sprint-1/Python/calculate_sum_and_product/calculate_sum_and_product.py b/Sprint-1/Python/calculate_sum_and_product/calculate_sum_and_product.py index cfd5cfd..36bc8f3 100644 --- a/Sprint-1/Python/calculate_sum_and_product/calculate_sum_and_product.py +++ b/Sprint-1/Python/calculate_sum_and_product/calculate_sum_and_product.py @@ -12,20 +12,50 @@ def calculate_sum_and_product(input_numbers: List[int]) -> Dict[str, int]: "sum": 10, // 2 + 3 + 5 "product": 30 // 2 * 3 * 5 } - Time Complexity: - Space Complexity: - Optimal time complexity: + + Time Complexity: O(n) - Single pass through the list + Space Complexity: O(1) - Only using constant extra space + Optimal Time Complexity: O(n) - Cannot do better than linear time """ + # OPTIMIZED IMPLEMENTATION: O(n) time complexity + # Previous implementation: O(2n) due to two separate loops + + sum_total = 0 # O(1) space + product = 1 # O(1) space + + # O(n) time complexity + for current_number in input_numbers: + sum_total += current_number # O(1) + product *= current_number # O(1) + + return {"sum": sum_total, "product": product} + + +# ORIGINAL IMPLEMENTATION (for comparison): +""" +def calculate_sum_and_product(input_numbers: List[int]) -> Dict[str, int]: # Edge case: empty list if not input_numbers: return {"sum": 0, "product": 1} sum = 0 - for current_number in input_numbers: + for current_number in input_numbers: # First pass: O(n) sum += current_number product = 1 - for current_number in input_numbers: + for current_number in input_numbers: # Second pass: O(n) product *= current_number - return {"sum": sum, "product": product} + return {"sum": sum, "product": product} # Total: O(2n) = O(n) time + +COMPLEXITY ANALYSIS OF ORIGINAL: +- First loop: O(n) iterations to calculate sum +- Second loop: O(n) iterations to calculate product +- Total: O(2n) = O(n) time complexity +- Space: O(1) - only using loop variables + +IMPROVEMENTS MADE: +1. Reduced from 2n to n operations (50% fewer iterations) +2. Single pass through list instead of two separate loops +3. Same O(n) time complexity but with better constant factors +""" diff --git a/Sprint-1/Python/find_common_items/find_common_items.py b/Sprint-1/Python/find_common_items/find_common_items.py index 478e2ef..b94bc63 100644 --- a/Sprint-1/Python/find_common_items/find_common_items.py +++ b/Sprint-1/Python/find_common_items/find_common_items.py @@ -9,13 +9,49 @@ def find_common_items( """ Find common items between two arrays. - Time Complexity: - Space Complexity: - Optimal time complexity: + Time Complexity: O(n + m) - Single pass through both sequences + Space Complexity: O(min(n, m)) - Set size bounded by smaller sequence + Optimal Time Complexity: O(n + m) - Cannot do better than linear time """ + # OPTIMIZED IMPLEMENTATION: O(n + m) time complexity + # Previous implementation: O(n × m) due to nested loops with linear search + + # Convert second sequence to set for O(1) lookup: O(m) time, O(m) space + second_set = set(second_sequence) + + # Find common items using set lookup: O(n) time + common_items = [] + for item in first_sequence: + if item in second_set and item not in common_items: + common_items.append(item) + + return common_items + + +# ORIGINAL IMPLEMENTATION (for comparison): +""" +def find_common_items( + first_sequence: Sequence[ItemType], second_sequence: Sequence[ItemType] +) -> List[ItemType]: common_items: List[ItemType] = [] - for i in first_sequence: - for j in second_sequence: - if i == j and i not in common_items: + for i in first_sequence: # O(n) iterations + for j in second_sequence: # O(m) iterations each + if i == j and i not in common_items: # O(k) linear search common_items.append(i) return common_items + +COMPLEXITY ANALYSIS OF ORIGINAL: +- Outer loop: O(n) iterations through first_sequence +- Inner loop: O(m) iterations through second_sequence +- Linear search: O(k) for 'i not in common_items' check +- Total: O(n × m × k) time complexity in worst case +- Space: O(n) for common_items list + +PERFORMANCE ISSUES: +- Quadratic time complexity O(n × m) from nested loops + +IMPROVEMENTS MADE: +1. Reduced from O(n × m × k) to O(n + m) time complexity +2. Set lookup is O(1) vs nested iteration O(m) +3. Single pass through first_sequence +""" diff --git a/Sprint-1/Python/has_pair_with_sum/has_pair_with_sum.py b/Sprint-1/Python/has_pair_with_sum/has_pair_with_sum.py index fe2da51..c333a6a 100644 --- a/Sprint-1/Python/has_pair_with_sum/has_pair_with_sum.py +++ b/Sprint-1/Python/has_pair_with_sum/has_pair_with_sum.py @@ -7,12 +7,48 @@ def has_pair_with_sum(numbers: List[Number], target_sum: Number) -> bool: """ Find if there is a pair of numbers that sum to a target value. - Time Complexity: - Space Complexity: - Optimal time complexity: + Time Complexity: O(n) - Single pass through the list + Space Complexity: O(n) - Set to store seen numbers + Optimal Time Complexity: O(n) - Cannot do better than linear time """ - for i in range(len(numbers)): - for j in range(i + 1, len(numbers)): - if numbers[i] + numbers[j] == target_sum: + # OPTIMIZED IMPLEMENTATION: O(n) time complexity + # Previous implementation: O(n²) due to nested loops + + seen = set() # O(n) space for storing seen numbers + + # Single pass through list: O(n) time complexity + for num in numbers: + complement = target_sum - num + + # Check if complement exists in seen numbers: O(1) lookup + if complement in seen: + return True + + # Add current number to seen set: O(1) operation + seen.add(num) + + return False + +# ORIGINAL IMPLEMENTATION (for comparison): +""" +def has_pair_with_sum(numbers: List[Number], target_sum: Number) -> bool: + for i in range(len(numbers)): # O(n) iterations + for j in range(i + 1, len(numbers)): # O(n) iterations each + if numbers[i] + numbers[j] == target_sum: # O(1) comparison return True return False + +COMPLEXITY ANALYSIS OF ORIGINAL: +- Outer loop: O(n) iterations +- Inner loop: O(n) iterations for each outer iteration +- Total: O(n²) time complexity +- Space: O(1) - only using loop variables + +PERFORMANCE ISSUES: +- Quadratic time complexity O(n²) + +IMPROVEMENTS MADE: +1. Reduced from O(n²) to O(n) time complexity +2. Single pass through list instead of nested loops +3. Set lookup is O(1) vs nested iteration O(n) +""" diff --git a/Sprint-1/Python/remove_duplicates/remove_duplicates.py b/Sprint-1/Python/remove_duplicates/remove_duplicates.py index c9fdbe8..029f3ae 100644 --- a/Sprint-1/Python/remove_duplicates/remove_duplicates.py +++ b/Sprint-1/Python/remove_duplicates/remove_duplicates.py @@ -7,19 +7,53 @@ def remove_duplicates(values: Sequence[ItemType]) -> List[ItemType]: """ Remove duplicate values from a sequence, preserving the order of the first occurrence of each value. - Time complexity: - Space complexity: - Optimal time complexity: + Time Complexity: O(n) - Single pass through the sequence + Space Complexity: O(n) - Set to track seen elements + Optimal Time Complexity: O(n) - Cannot do better than linear time """ + # OPTIMIZED IMPLEMENTATION: O(n) time complexity + # Previous implementation: O(n²) due to nested loops checking each element + + seen = set() # O(n) + unique_items = [] # O(n) + + # O(n) time complexity + for value in values: + # O(1) lookup + if value not in seen: + seen.add(value) # O(1) + unique_items.append(value) # O(1) + + return unique_items + + +# ORIGINAL IMPLEMENTATION (for comparison): +""" +def remove_duplicates(values: Sequence[ItemType]) -> List[ItemType]: unique_items = [] - for value in values: + for value in values: # O(n) iterations is_duplicate = False - for existing in unique_items: - if value == existing: + for existing in unique_items: # O(k) iterations (k grows with unique elements) + if value == existing: # O(1) comparison is_duplicate = True break if not is_duplicate: - unique_items.append(value) + unique_items.append(value) # O(1) operation return unique_items + +COMPLEXITY ANALYSIS OF ORIGINAL: +- Outer loop: O(n) iterations through values +- Inner loop: O(k) iterations through unique_items (k grows with each unique element) +- Worst case: O(n²) when all elements are unique +- Space: O(n) for unique_items list + +PERFORMANCE ISSUES: +- Quadratic time complexity O(n²) in worst case + +IMPROVEMENTS MADE: +1. Reduced from O(n²) to O(n) time complexity +2. Set lookup is O(1) vs linear search O(k) +3. Single pass through input sequence +"""