diff --git a/Problem1.py b/Problem1.py new file mode 100644 index 00000000..2b5449fb --- /dev/null +++ b/Problem1.py @@ -0,0 +1,47 @@ +## Problem1 +# Subsets (https://leetcode.com/problems/subsets/) +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + """ + Time Complexity: O(N * 2^N) + - There are 2^N possible subsets for an array of size N. + - In the base case, creating a shallow copy of the path (using list(path)) takes O(N) time. + + Space Complexity: O(N) + - The maximum depth of the recursion tree is N. + - The auxiliary `path` array stores at most N elements. + - Note: This does not include the O(N * 2^N) space required to hold the final result array. + """ + result = [] + + def helper(idx, path): + nonlocal result, nums + + # Base case: We have made a choose/don't choose decision for every element. + # We reached the end of the array, so the current path is a valid subset. + if idx == len(nums): + result.append(list(path)) # Create a shallow copy to prevent reference mutation + return + + # --- Recursive Logic (Backtracking) --- + + # Option 1: Not Choose Case + # We skip the current element at 'idx' and move to the next element. + # The path remains unmodified. + helper(idx + 1, path) + + # Option 2: Choose Case + # We include the current element at 'idx' in our subset path. + path.append(nums[idx]) + + # Explore all further possibilities with this element included. + helper(idx + 1, path) + + # Backtrack: Remove the element we just added before returning to the previous + # level of the recursion tree, so it doesn't leak into other parallel branches. + path.pop() + + # Start the recursion at index 0 with an empty current subset. + helper(0, []) + + return result \ No newline at end of file diff --git a/Problem2.py b/Problem2.py new file mode 100644 index 00000000..9d65b47d --- /dev/null +++ b/Problem2.py @@ -0,0 +1,60 @@ +## Problem2 + +# Palindrome Partitioning(https://leetcode.com/problems/palindrome-partitioning/) +class Solution: + def partition(self, s: str) -> List[List[str]]: + """ + Time Complexity: O(N * 2^N) + - The Subsets (2^N): In the worst-case scenario where every substring is a palindrome + (e.g., "aaaa"), there are 2^(N-1) possible ways to partition the string. + - The Palindrome Check (N): For each of those possible partitions, we slice strings + and check if they are palindromes, taking O(N) time. + - Total: O(N * 2^N), where N is the length of string s. + + Space Complexity: O(N) + - Recursion Stack: The maximum depth of the recursive call stack is N (happens when + partitioned into single characters). + - Path Variable: The 'path' array can hold a maximum of N strings at any given time. + - Total: O(N) + O(N) = O(N). (Note: This excludes the space required to store the + final 'result' array). + """ + + # This will store all of our valid palindrome partitions + result = [] + + def helper(s, pivot, path): + nonlocal result + n = len(s) + + # --- BASE CASE --- + # If our pivot reaches the end of the string (n), it means we have + # successfully partitioned the entire string into valid palindromes. + if pivot == n: + # We append a *copy* of the current path (using list()) because + # 'path' is a reference and will be modified by future recursive calls. + result.append(list(path)) + return + + # --- RECURSIVE LOGIC & BACKTRACKING --- + # We iterate through the string starting from our current 'pivot'. + # 'i' represents the ending index of the substring we are evaluating. + for i in range(pivot, n): + # Extract the current substring from pivot to i + curr = s[pivot:i+1] + + # Check if the extracted substring is a palindrome + if curr == curr[::-1]: + # 1. CHOOSE: Add the valid palindrome to our current path + path.append(curr) + + # 2. EXPLORE: Recursively partition the rest of the string. + # The new starting point (pivot) for the remaining string is i + 1. + helper(s, i + 1, path) + + # 3. UN-CHOOSE (Backtrack): Remove the last added substring + # so we can continue the loop and try longer substrings from the original pivot. + path.pop() + + # Kick off the recursion starting at index 0 with an empty path + helper(s, 0, []) + return result \ No newline at end of file