diff --git a/combination-sum/alphaorderly.py b/combination-sum/alphaorderly.py new file mode 100644 index 0000000000..2ab9b68f50 --- /dev/null +++ b/combination-sum/alphaorderly.py @@ -0,0 +1,51 @@ + +""" +Time Complexity: O(N^target) +Space Complexity: O(target) + +Classic backtracking approach. +- Use a helper function to backtrack and generate all possible combinations. +""" +# class Solution: +# def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: +# N = len(candidates) +# candidates.sort() + +# ans = [] +# app = [] + +# def backtracking(last: int, left: int) -> None: +# if left == 0: +# ans.append(app[:]) +# return + +# for i in range(last, N): +# if candidates[i] > left: +# continue + +# app.append(candidates[i]) +# backtracking(i, left - candidates[i]) +# app.pop() + +# backtracking(0, target) + +# return ans + +""" +Time Complexity: O(N * target) +Space Complexity: O(target) + +- Use a dynamic programming approach to store the combinations that sum to each target. +- dp[j] is a list of lists that sum to j. +""" +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + dp = [list() for _ in range(target + 1)] + dp[0] = [[]] + + for c in candidates: + for j in range(c, target + 1): + for partial in dp[j - c]: + dp[j].append(partial + [c]) + + return dp[-1] diff --git a/decode-ways/alphaorderly.py b/decode-ways/alphaorderly.py new file mode 100644 index 0000000000..123e80b1b7 --- /dev/null +++ b/decode-ways/alphaorderly.py @@ -0,0 +1,31 @@ +""" +Time Complexity: O(N) +Space Complexity: O(1) + +prev_2 : number of ways to decode the string ending with the previous two characters +prev_1 : number of ways to decode the string ending with the previous character +new_prev : number of ways to decode the string ending with the current character +""" +class Solution: + def numDecodings(self, s: str) -> int: + N = len(s) + + if s[0] == "0": + return 0 + + if N == 1: + return 1 + + prev_2 = 1 + prev_1 = int(1 <= int(s[0] + s[1]) <= 26) + int(s[1] != "0") + + for i in range(2, N): + new_prev = 0 + if 1 <= int(s[i - 1] + s[i]) <= 26 and s[i - 1] != "0": + new_prev += prev_2 + if s[i] != "0": + new_prev += prev_1 + + prev_2, prev_1 = prev_1, new_prev + + return prev_1 diff --git a/maximum-subarray/alphaorderly.py b/maximum-subarray/alphaorderly.py new file mode 100644 index 0000000000..7ccc23d8f8 --- /dev/null +++ b/maximum-subarray/alphaorderly.py @@ -0,0 +1,71 @@ + + +""" +Time Complexity: O(NLogN) +Space Complexity: O(N) ( Reason: Recursive stack pointer for every element ) + +Divide and Conquer Approach + +1. Divide the array into two halves +2. Find the maximum subarray sum in the left half +3. Find the maximum subarray sum in the right half +4. Find the maximum subarray sum that crosses the midpoint +5. Return the maximum of the three sums +""" +# class Solution: +# def maxSubArray(self, nums: List[int]) -> int: + +# def divide(start: int, end: int) -> int: +# if start >= end: +# return nums[start] + +# mid = (start + end) // 2 + +# left = divide(start, mid) +# right = divide(mid + 1, end) + +# left_largest = -float('inf') +# right_largest = -float('inf') + +# left_acc = 0 +# right_acc = 0 + +# left_index = mid +# right_index = mid + 1 + +# while left_index >= start: +# left_acc += nums[left_index] +# left_largest = max(left_largest, left_acc) +# left_index -= 1 + +# while right_index <= end: +# right_acc += nums[right_index] +# right_largest = max(right_largest, right_acc) +# right_index += 1 + +# return max(left_largest + right_largest, left, right) + +# return divide(0, len(nums) - 1) + + + + +""" +Time Complexity: O(N) +Space Complexity: O(1) + +prev : maximum sum of the subarray ending with the previous element +ans : maximum sum of the subarray +curr : maximum sum of the subarray ending with the current element +""" +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + N = len(nums) + prev = nums[0] + ans = nums[0] + + for i in range(1, N): + prev = max(nums[i], prev + nums[i]) + ans = max(ans, prev) + + return ans diff --git a/number-of-1-bits/alphaorderly.py b/number-of-1-bits/alphaorderly.py new file mode 100644 index 0000000000..a334b0b209 --- /dev/null +++ b/number-of-1-bits/alphaorderly.py @@ -0,0 +1,11 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + ans = 0 + while n: + ans += n & 1 + n >>= 1 + return ans + +# class Solution: +# def hammingWeight(self, n: int) -> int: +# return bin(n).count('1') diff --git a/valid-palindrome/alphaorderly.py b/valid-palindrome/alphaorderly.py new file mode 100644 index 0000000000..d203dff82f --- /dev/null +++ b/valid-palindrome/alphaorderly.py @@ -0,0 +1,42 @@ +""" +Time Complexity: O(N) +Space Complexity: O(N) + +- Process string with lower() and isalnum() to remove non-alphanumeric characters +- Check if the processed string is a palindrome by comparing it to its reverse +""" +# class Solution: +# def isPalindrome(self, s: str) -> bool: +# processed = "".join(ch.lower() for ch in s if ch.isalnum()) + +# return processed == processed[::-1] + +""" +Time Complexity: O(N) +Space Complexity: O(1) + +- Use two pointers to check if the string is a palindrome +- Skip non-alphanumeric characters +- Compare characters from both ends towards the center +""" +class Solution: + def isPalindrome(self, s: str) -> bool: + N = len(s) + + left, right = 0, N - 1 + + while True: + while not s[left].isalnum() and left < right: + left += 1 + while not s[right].isalnum() and left < right: + right -= 1 + + if left >= right: + break + + if s[left].lower() != s[right].lower(): + return False + + left, right = left + 1, right - 1 + + return True