From c44c6bdd74b9a3139c19723613bfdbe192d38a3e Mon Sep 17 00:00:00 2001 From: Sadaf <137484958+SadafKausar2025@users.noreply.github.com> Date: Fri, 14 Jun 2024 12:38:02 +0530 Subject: [PATCH 1/3] Added leetcode-216 Combination sum III --- dsa-problems/leetcode-problems/0200-0299.md | 2 +- .../0209-minimum-size-subarray-sum.md | 6 + .../0200-0299/0216-Combination-sum-III.md | 345 ++++++++++++++++++ 3 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md diff --git a/dsa-problems/leetcode-problems/0200-0299.md b/dsa-problems/leetcode-problems/0200-0299.md index 05285fd0a..4f9845396 100644 --- a/dsa-problems/leetcode-problems/0200-0299.md +++ b/dsa-problems/leetcode-problems/0200-0299.md @@ -110,7 +110,7 @@ export const problems = [ "problemName": "216. Combination Sum III", "difficulty": "Medium", "leetCodeLink": "https://leetcode.com/problems/combination-sum-iii", -"solutionLink": "#" +"solutionLink": "/dsa-solutions/lc-solutions/0200-0299/combination-sum-III" }, { "problemName": "217. Contains Duplicate", diff --git a/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md b/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md index d7c1a9b1e..13034fb0b 100644 --- a/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md +++ b/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md @@ -217,6 +217,12 @@ Example 3: +## Time and Space Complexity + + The time complexity of the code is O(n), where n is the length of the input list nums. This is because there are two pointers i and j, both of which travel across the list at most once. The inner while loop only increases j and decreases the sum s until the sum is less than the target, but j can never be increased more than n times throughout the execution of the algorithm. Therefore, each element is processed at most twice, once when it is added to s and once when it is subtracted, leading to a linear time complexity. + + The space complexity of the code is O(1), which means it requires a constant amount of additional space. This is because the algorithm only uses a fixed number of single-value variables (n, ans, s, j, i, x) and does not utilize any data structures that grow with the size of the input. + ## video lecture 1, there are no valid combination. +``` + +## Solutions + +### Intuition + + To find the solution, we can utilize a Depth First Search (DFS) algorithm. DFS will help us explore all possible combinations of numbers recursively while adhering to the constraints. Here's the intuition behind using DFS for this problem: + + 1. We begin by considering numbers from 1 to 9 and use each of them as a starting point of a combination. + + 2. To build a combination, we add a number to the current combination (t in the given code) and recursively call the DFS function to add the next number. + + 3. While adding the new number, we have three conditions to check: + a. We must not exceed the target sum n. + b. We should not use more than k numbers. + c. We cannot use numbers greater than 9. + + 4. If the sum of numbers in the current combination equals n and we have used exactly k numbers, then we found a valid combination which we add to the answer list (ans). + + 5. After exploring a number's inclusion, we backtrack by removing the number from the current combination and exploring the possibility of not including that number. + + 6. Through this process of including and excluding each number, and backtracking after exploring each possibility, we ensure that all valid combinations are found. + + 7. Each combination is built up incrementally from the smaller numbers towards the larger ones to avoid repeated combinations and maintain uniqueness. + +The beauty of DFS in this situation is that it inherently avoids duplicates and handles the "each number used at most once" constraint by the recursive nature of its implementation. DFS explores each branch fully (one specific number added vs. not added) before backtracking, which helps cover all potential unique combinations without repetition. + +## Solution Approach + +The provided solution uses a Depth First Search (DFS) algorithm to explore all possible unique combinations of numbers that add up to n using at most k numbers. Here is a step-by-step breakdown of the approach, referring to specific parts of the implementation: + +1. DFS Function: The function dfs(i: int, s: int) is a recursive function where i represents the current number that we are considering adding to the combination, and s is the remaining sum that we need to achieve. The solution initializes the function by calling dfs(1, n). + +2. Base Conditions: + + a. The first base condition checks whether the remaining sum s is 0. If s is 0 and we have exactly k numbers in our temporary combination t, then we have found a valid combination. We then append a a copy of t (using t[:] to create a copy) to our answers list ans. + + b. The second base condition checks whether the current number i is greater than 9 or i is greater than the remaining sum s or we have already selected k numbers. In any of these cases, the function returns without making further recursive calls since no valid combination can be completed under these conditions. + +3. Choosing the Current Number: + + We add the current number i to our temporary combination t. This is the "exploring the possibility of including the number" part of the DFS. + +4. Recursive Call for Next Number: + + After including the current number, we make a recursive call to dfs(i + 1, s - i). This call will explore combinations where the current number i is part of the solution. By passing i + 1, we are ensuring that the same number is not used more than once. By passing s - i, we are reducing the sum by the value of the number we've included. + +5. Backtracking: + + After the recursive call, we backtrack by removing the last number that we added — t.pop(). This is where we explore the possibility of excluding the current number. + +6. Recursive Call without the Current Number: + + Another recursive call dfs(i + 1, s) is then made. This call will explore combinations that exclude the current number i. + +7. Initialization: + + The function maintains a list ans to collect all valid combinations found by the DFS. + A list t is used to build a temporary combination that is being explored. + +8. Return Result: + + Once the initial call to dfs(1, n) has completed, all possible combinations have been explored, and the ans list contains all valid combinations as required by the problem. This list is returned as the final result. + +Through the combination of recursive DFS, building combinations incrementally, making sure that each number is used at most once, and backtracking after exploring each possibility, the solution efficiently finds all the valid combinations that sum up to n. The use of a temporary list t for tracking the current combination and the answer list ans are examples of data structures used in this problem to store intermediate and final results, respectively. + + + + + ```cpp + #include + #include + using namespace std; + + class Solution { + public: + vector> combinationSum3(int k, int n) { + vector> output; + vector currentSeq; + vector nums(9); + iota(nums.begin(), nums.end(), 1); + + combination(nums, 0, n, k, currentSeq, output); + + return output; + } + + private: + bool combination(vector& nums, int pos, int target, int length, vector& currentSeq, vector>& output) { + if (currentSeq.size() > length) { + return false; + } + if (target == 0 && currentSeq.size() == length) { + output.push_back(currentSeq); + return true; + } + else if (target < 0) { + return false; + } + + for (int i = pos; i < nums.size(); ++i) { + currentSeq.push_back(nums[i]); + + auto result = combination(nums, i + 1, target - nums[i], length, currentSeq, output); + + currentSeq.pop_back(); + + if (!result) { + return true; + } + } + return true; + } + }; + ``` + + + + ```java + import java.util.*; + + public class Solution { + public List> combinationSum3(int k, int n) { + List> output = new ArrayList<>(); + List currentSeq = new ArrayList<>(); + List nums = new ArrayList<>(); + for (int i = 1; i <= 9; i++) { + nums.add(i); + } + + combination(nums, 0, n, k, currentSeq, output); + + return output; + } + + private boolean combination(List nums, int pos, int target, int length, List currentSeq, List> output) { + if (currentSeq.size() > length) { + return false; + } + if (target == 0 && currentSeq.size() == length) { + output.add(new ArrayList<>(currentSeq)); + return true; + } else if (target < 0) { + return false; + } + + for (int i = pos; i < nums.size(); ++i) { + currentSeq.add(nums.get(i)); + + boolean result = combination(nums, i + 1, target - nums.get(i), length, currentSeq, output); + + currentSeq.remove(currentSeq.size() - 1); + + if (!result) { + return true; + } + } + return true; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + System.out.println(solution.combinationSum3(3, 7)); // Output: [[1, 2, 4]] + System.out.println(solution.combinationSum3(3, 9)); // Output: [[1, 2, 6], [1, 3, 5], [2, 3, 4]] + } + } + ``` + + + + ```python + from typing import List + + class Solution: + def combinationSum3(self, k: int, n: int) -> List[List[int]]: + def combination(nums, pos, target, length, currentSeq, output): + if len(currentSeq) > length: + return False + if target == 0 and len(currentSeq) == length: + output.append(list(currentSeq)) + return True + elif target < 0: + return False + + for i in range(pos, len(nums)): + currentSeq.append(nums[i]) + + result = combination(nums, i + 1, target - nums[i], length, currentSeq, output) + + currentSeq.pop() + + if not result: + return True + return True + + output = [] + currentSeq = [] + nums = list(range(1, 10)) + + combination(nums, 0, n, k, currentSeq, output) + + return output + ``` + + + + ```c + #include + #include + #include + + void combination(int* nums, int pos, int target, int length, int* currentSeq, int currentLen, int*** output, int* outputSize, int** columnSizes) { + if (currentLen > length) { + return; + } + if (target == 0 && currentLen == length) { + (*outputSize)++; + *output = realloc(*output, (*outputSize) * sizeof(int*)); + (*output)[*outputSize - 1] = malloc(currentLen * sizeof(int)); + (*columnSizes) = realloc(*columnSizes, (*outputSize) * sizeof(int)); + for (int i = 0; i < currentLen; i++) { + (*output)[*outputSize - 1][i] = currentSeq[i]; + } + (*columnSizes)[*outputSize - 1] = currentLen; + return; + } else if (target < 0) { + return; + } + + for (int i = pos; i < 9; i++) { + currentSeq[currentLen] = nums[i]; + combination(nums, i + 1, target - nums[i], length, currentSeq, currentLen + 1, output, outputSize, columnSizes); + } + } + + int** combinationSum3(int k, int n, int* returnSize, int** returnColumnSizes) { + int* nums = malloc(9 * sizeof(int)); + for (int i = 0; i < 9; i++) { + nums[i] = i + 1; + } + + int* currentSeq = malloc(k * sizeof(int)); + int** output = NULL; + int* columnSizes = NULL; + int outputSize = 0; + + combination(nums, 0, n, k, currentSeq, 0, &output, &outputSize, &columnSizes); + + *returnSize = outputSize; + *returnColumnSizes = columnSizes; + + free(nums); + free(currentSeq); + + return output; + } + ``` + + + + +## Time and Space Complexity + + The given Python code defines a method combinationSum3 that finds all possible combinations of k different numbers that add up to a number n, where each number is from 1 to 9 (inclusive) and each combination is unique. + +### Time Complexity + + The time complexity of this function can be analyzed by looking at the recursive dfs calls. Each call to dfs potentially makes two further calls, corresponding to including the current number i or excluding it. We can view this as a binary tree of decisions, where at each step, we decide whether to include a number in our current combination (t.append(i)) or not (dfs(i + 1, s)). + + Each number between 1 and 9 is considered exactly once in the context of a particular combination, and there are 9 choices at the first call, 8 at the second, and so forth. However, the depth of our recursion is limited by k (the size of each combination) and the fact that we do not consider subsequent numbers once we reach a sum greater than n or a combination length equal to k. + + Therefore, the time complexity is O(9! / (9 - k)!) in the worst case (when n is large enough to allow all combinations of k numbers). Note that since k < 9, this time complexity remains within a polynomial bound with respect to 9 (the number of different numbers we can pick). + +### Space Complexity + + The space complexity is determined by the space needed for the recursive call stack and the space used to store the combinations. In the worst case, the recursion can go as deep as k, as we stop further recursion when the length of the temporary list t reaches k. Therefore the recursion call stack will contribute O(k). + + The space for storing all the combinations also needs to be considered. We have a list of lists to store the valid combinations, and, at most, each combination contains k elements. In the worst case, the number of combinations stored will also be bounded by the total number of combinations of k numbers out of 9, which is O(9! / (k!(9 - k)!)) (this is the binomial coefficient representing the number of ways to choose k distinct integers from a set of 9). + + However, because these combinations are part of the output, we often do not count this as extra space in terms of space complexity analysis (since the space is required to represent the output). Thus the space complexity is usually considered to be O(k), which accounts only for the recursion depth and not the output storage. + + Combining both the recursion call stack and the output storage, and if we were to include the output as part of the space complexity, our total space complexity would be O(9! / (k!(9 - k)!) + k). + +## Video Lecture + + From 2de8c3b649bdda22a3acd600eb852c7274b83fb1 Mon Sep 17 00:00:00 2001 From: Sadaf <137484958+SadafKausar2025@users.noreply.github.com> Date: Fri, 14 Jun 2024 12:53:01 +0530 Subject: [PATCH 2/3] corrected_video --- .../lc-solutions/0200-0299/0216-Combination-sum-III.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md b/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md index f18c0fc0c..e4f17bba0 100644 --- a/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md +++ b/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md @@ -338,7 +338,7 @@ Through the combination of recursive DFS, building combinations incrementally, m ## Video Lecture Date: Fri, 14 Jun 2024 14:28:16 +0530 Subject: [PATCH 3/3] corrected --- .../0200-0299/0209-minimum-size-subarray-sum.md | 4 ++-- .../lc-solutions/0200-0299/0216-Combination-sum-III.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md b/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md index 13034fb0b..8485d5265 100644 --- a/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md +++ b/dsa-solutions/lc-solutions/0200-0299/0209-minimum-size-subarray-sum.md @@ -219,9 +219,9 @@ Example 3: ## Time and Space Complexity - The time complexity of the code is O(n), where n is the length of the input list nums. This is because there are two pointers i and j, both of which travel across the list at most once. The inner while loop only increases j and decreases the sum s until the sum is less than the target, but j can never be increased more than n times throughout the execution of the algorithm. Therefore, each element is processed at most twice, once when it is added to s and once when it is subtracted, leading to a linear time complexity. + The time complexity of the code is $O(n)$, where n is the length of the input list nums. This is because there are two pointers i and j, both of which travel across the list at most once. The inner while loop only increases j and decreases the sum s until the sum is less than the target, but j can never be increased more than n times throughout the execution of the algorithm. Therefore, each element is processed at most twice, once when it is added to s and once when it is subtracted, leading to a linear time complexity. - The space complexity of the code is O(1), which means it requires a constant amount of additional space. This is because the algorithm only uses a fixed number of single-value variables (n, ans, s, j, i, x) and does not utilize any data structures that grow with the size of the input. + The space complexity of the code is $O(1)$, which means it requires a constant amount of additional space. This is because the algorithm only uses a fixed number of single-value variables (n, ans, s, j, i, x) and does not utilize any data structures that grow with the size of the input. ## video lecture diff --git a/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md b/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md index e4f17bba0..afacfa3a6 100644 --- a/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md +++ b/dsa-solutions/lc-solutions/0200-0299/0216-Combination-sum-III.md @@ -327,13 +327,13 @@ Through the combination of recursive DFS, building combinations incrementally, m ### Space Complexity - The space complexity is determined by the space needed for the recursive call stack and the space used to store the combinations. In the worst case, the recursion can go as deep as k, as we stop further recursion when the length of the temporary list t reaches k. Therefore the recursion call stack will contribute O(k). + The space complexity is determined by the space needed for the recursive call stack and the space used to store the combinations. In the worst case, the recursion can go as deep as k, as we stop further recursion when the length of the temporary list t reaches k. Therefore the recursion call stack will contribute $O(k)$. - The space for storing all the combinations also needs to be considered. We have a list of lists to store the valid combinations, and, at most, each combination contains k elements. In the worst case, the number of combinations stored will also be bounded by the total number of combinations of k numbers out of 9, which is O(9! / (k!(9 - k)!)) (this is the binomial coefficient representing the number of ways to choose k distinct integers from a set of 9). + The space for storing all the combinations also needs to be considered. We have a list of lists to store the valid combinations, and, at most, each combination contains k elements. In the worst case, the number of combinations stored will also be bounded by the total number of combinations of k numbers out of 9, which is $O(9! / (k!(9 - k)!))$ (this is the binomial coefficient representing the number of ways to choose k distinct integers from a set of 9). - However, because these combinations are part of the output, we often do not count this as extra space in terms of space complexity analysis (since the space is required to represent the output). Thus the space complexity is usually considered to be O(k), which accounts only for the recursion depth and not the output storage. + However, because these combinations are part of the output, we often do not count this as extra space in terms of space complexity analysis (since the space is required to represent the output). Thus the space complexity is usually considered to be $O(k)$, which accounts only for the recursion depth and not the output storage. - Combining both the recursion call stack and the output storage, and if we were to include the output as part of the space complexity, our total space complexity would be O(9! / (k!(9 - k)!) + k). + Combining both the recursion call stack and the output storage, and if we were to include the output as part of the space complexity, our total space complexity would be $O(9! / (k!(9 - k)!) + k)$. ## Video Lecture