From 4a809cffd67a5c62f0582126b62d301c23f17ed7 Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:43:10 +0200 Subject: [PATCH 1/7] Refactored calculateSumAndProduct to make the app more effecient and less expensive --- .../calculateSumAndProduct.js | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js b/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js index ce738c33..451a13be 100644 --- a/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js +++ b/Sprint-1/JavaScript/calculateSumAndProduct/calculateSumAndProduct.js @@ -5,30 +5,36 @@ * and the "product" is every number multiplied together * so for example: [2, 3, 5] would return * { - * "sum": 10, // 2 + 3 + 5 - * "product": 30 // 2 * 3 * 5 + * "sum": 10, + * "product": 30 * } * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Time Complexity: O(n) + * The function loops through the array once, processing each element exactly once. + * + * Space Complexity: O(1) + * Only two variables (sum and product) are used, regardless of the input size. + * + * Optimal Time Complexity: O(n) + * This is the optimal time complexity because every element must be read at least + * once to calculate both the sum and the product. * * @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; - } + let sum = 0 + let product = 1 - let product = 1; + // Refactored to use a single loop instead of two. + // This reduces the number of iterations but keeps the time complexity at O(n). for (const num of numbers) { - product *= num; + sum += num + product *= num } return { - sum: sum, - product: product, - }; + sum, + product, + } } From fae7582662f261450ea46424e5cc07db01784a2e Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:48:53 +0200 Subject: [PATCH 2/7] FindcommonItems can not be refactored because the function already following the best code complexity --- .../JavaScript/findCommonItems/findCommonItems.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Sprint-1/JavaScript/findCommonItems/findCommonItems.js b/Sprint-1/JavaScript/findCommonItems/findCommonItems.js index 5619ae5d..b67766b4 100644 --- a/Sprint-1/JavaScript/findCommonItems/findCommonItems.js +++ b/Sprint-1/JavaScript/findCommonItems/findCommonItems.js @@ -1,9 +1,16 @@ /** * Finds common items between two arrays. * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Time Complexity: O(n × m) + * The function loops through the first array and uses `includes()` to search + * the second array for each element. + * + * Space Complexity: O(n) + * A new array is created to store the matching items. + * + * Optimal Time Complexity: O(n × m) + * The complexity cannot be reduced without using an additional lookup + * data structure such as a Set or a hash map. * * @param {Array} firstArray - First array to compare * @param {Array} secondArray - Second array to compare @@ -11,4 +18,4 @@ */ export const findCommonItems = (firstArray, secondArray) => [ ...new Set(firstArray.filter((item) => secondArray.includes(item))), -]; +] From 056d7e2d238d22523b76c11fc44d4627e7609c3a Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:54:00 +0200 Subject: [PATCH 3/7] Refactoring haspairwithsum through set class --- .../hasPairWithSum/hasPairWithSum.js | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js b/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js index dd2901f6..59f9c6f9 100644 --- a/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js +++ b/Sprint-1/JavaScript/hasPairWithSum/hasPairWithSum.js @@ -1,21 +1,29 @@ /** * Find if there is a pair of numbers that sum to a given target value. * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Original Time Complexity: O(n²) + * The original code uses nested loops to compare every possible pair of numbers. + * + * Space Complexity: O(n) + * A Set is used to store numbers that have already been seen. + * + * Optimal Time Complexity: O(n) + * The array is traversed once, and Set lookups are O(1) on average. * * @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; - } + const seen = new Set() + + for (const num of numbers) { + if (seen.has(target - num)) { + return true } + + seen.add(num) } - return false; + + return false } From 36769e7fb57199a5f84ed0e27ce0f657aedcbd41 Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:56:30 +0200 Subject: [PATCH 4/7] Refactoring nested loops to one set --- .../removeDuplicates/removeDuplicates.mjs | 43 ++++++------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs b/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs index dc5f7711..bb558090 100644 --- a/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs +++ b/Sprint-1/JavaScript/removeDuplicates/removeDuplicates.mjs @@ -1,36 +1,19 @@ /** - * Remove duplicate values from a sequence, preserving the order of the first occurrence of each value. + * Remove duplicate items from a sequence. * - * Time Complexity: - * Space Complexity: - * Optimal Time Complexity: + * Original Time Complexity: O(n²) + * The original code uses a nested loop to compare every item with the + * previously collected unique items. * - * @param {Array} inputSequence - Sequence to remove duplicates from - * @returns {Array} New sequence with duplicates removed + * Space Complexity: O(n) + * A new collection is created to store unique items. + * + * Optimal Time Complexity: O(n) + * A Set allows constant-time lookups, so each item only needs to be checked once. + * + * @param {Array} inputSequence - Sequence containing possible duplicates + * @returns {Array} Sequence containing only unique items */ 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; + return [...new Set(inputSequence)] } From 26c8f0b4cfe2dcdc860d2975de1ef80d194805aa Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:27:21 +0200 Subject: [PATCH 5/7] Implemented linked list in Python --- Sprint-2/implement_linked_list/linked_list.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Sprint-2/implement_linked_list/linked_list.py b/Sprint-2/implement_linked_list/linked_list.py index e69de29b..aa099a32 100644 --- a/Sprint-2/implement_linked_list/linked_list.py +++ b/Sprint-2/implement_linked_list/linked_list.py @@ -0,0 +1,42 @@ +class Node: + def __init__(self, value): + self.value = value + self.next = None + self.previous = None + + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def push_head(self, value): + node = Node(value) + node.next = self.head + + if self.head is not None: + self.head.previous = node + else: + self.tail = node + + self.head = node + return node + + def pop_tail(self): + node = self.tail + self.remove(node) + return node.value + + def remove(self, node): + if node.previous is not None: + node.previous.next = node.next + else: + self.head = node.next + + if node.next is not None: + node.next.previous = node.previous + else: + self.tail = node.previous + + node.next = None + node.previous = None From 2f9bbb5aa365236c7f603f162a2877169166b096 Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:34:15 +0200 Subject: [PATCH 6/7] implement LRU cache --- Sprint-2/implement_lru_cache/lru_cache.py | 60 +++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Sprint-2/implement_lru_cache/lru_cache.py b/Sprint-2/implement_lru_cache/lru_cache.py index e69de29b..0264c254 100644 --- a/Sprint-2/implement_lru_cache/lru_cache.py +++ b/Sprint-2/implement_lru_cache/lru_cache.py @@ -0,0 +1,60 @@ +class Node: + def __init__(self, key=None, value=None): + self.key = key + self.value = value + self.next = None + self.previous = None + + +class LruCache: + def __init__(self, limit): + if limit <= 0: + raise ValueError("limit must be positive") + + self.limit = limit + self.entries = {} + + # Sentinel nodes bound the list so add/remove never special-case + # empty lists or the ends of the list. + self.head = Node() + self.tail = Node() + self.head.next = self.tail + self.tail.previous = self.head + + def get(self, key): + node = self.entries.get(key) + if node is None: + return None + + self._move_to_front(node) + return node.value + + def set(self, key, value): + node = self.entries.get(key) + if node is not None: + node.value = value + self._move_to_front(node) + return + + node = Node(key, value) + self.entries[key] = node + self._add_to_front(node) + + if len(self.entries) > self.limit: + lru = self.tail.previous + self._remove(lru) + del self.entries[lru.key] + + def _move_to_front(self, node): + self._remove(node) + self._add_to_front(node) + + def _add_to_front(self, node): + node.next = self.head.next + node.previous = self.head + self.head.next.previous = node + self.head.next = node + + def _remove(self, node): + node.previous.next = node.next + node.next.previous = node.previous From f4034dfab0d424281648f14e905af3d8953bd8b6 Mon Sep 17 00:00:00 2001 From: Iheb Hamdi <67348203+hamdiheb@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:41:58 +0200 Subject: [PATCH 7/7] Improved with caches --- .../fibonacci/fibonacci.py | 10 +++++-- .../making_change/making_change.py | 27 ++++++++----------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Sprint-2/improve_with_caches/fibonacci/fibonacci.py b/Sprint-2/improve_with_caches/fibonacci/fibonacci.py index 60cc6671..e38981be 100644 --- a/Sprint-2/improve_with_caches/fibonacci/fibonacci.py +++ b/Sprint-2/improve_with_caches/fibonacci/fibonacci.py @@ -1,4 +1,10 @@ -def fibonacci(n): +def fibonacci(n, cache=None): + if cache is None: + cache = {} if n <= 1: return n - return fibonacci(n - 1) + fibonacci(n - 2) + if n in cache: + return cache[n] + result = fibonacci(n - 1, cache) + fibonacci(n - 2, cache) + cache[n] = result + return result diff --git a/Sprint-2/improve_with_caches/making_change/making_change.py b/Sprint-2/improve_with_caches/making_change/making_change.py index 255612e5..712e8f10 100644 --- a/Sprint-2/improve_with_caches/making_change/making_change.py +++ b/Sprint-2/improve_with_caches/making_change/making_change.py @@ -13,20 +13,15 @@ def ways_to_make_change(total: int) -> int: def ways_to_make_change_helper(total: int, coins: List[int]) -> int: """ Helper function for ways_to_make_change to avoid exposing the coins parameter to callers. + + Builds up a cache of ways[amount] = number of ways to make `amount` using the coins + considered so far, growing the cache one coin denomination at a time. """ - if total == 0 or len(coins) == 0: - return 0 - - ways = 0 - for coin_index in range(len(coins)): - coin = coins[coin_index] - count_of_coin = 1 - while coin * count_of_coin <= total: - total_from_coins = coin * count_of_coin - if total_from_coins == total: - ways += 1 - else: - intermediate = ways_to_make_change_helper(total - total_from_coins, coins=coins[coin_index+1:]) - ways += intermediate - count_of_coin += 1 - return ways + ways = [0] * (total + 1) + ways[0] = 1 + + for coin in coins: + for amount in range(coin, total + 1): + ways[amount] += ways[amount - coin] + + return ways[total]