diff --git a/probelm34.py b/probelm34.py new file mode 100644 index 00000000..c3f197ed --- /dev/null +++ b/probelm34.py @@ -0,0 +1,29 @@ +class Solution: + def sortColors(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + left = 0 #to catch 0s + right = len(nums)-1 #to catch 2s + mid = left #to iterate the array and to catch 1s + + while mid <= right: + if nums[mid] == 2: + nums[mid], nums[right] = nums[right], nums[mid] + right -= 1 #cant move mid here because left is not yet sorted. The value swapped from the right into mid is unknown. It can be 0,1,2 so we need to re-check it in next iteration. + + elif nums[mid] == 0: + nums[mid], nums[left] = nums[left], nums[mid] + left += 1 + mid += 1 #left is sorted so move mid. everything before mid was already processed, so the swapped value is guaranteed to be a 1. it can't be a 2 as its always taken care of first. + else: + mid += 1 + +# You only move mid when you are sure the value at mid is finalized. + +# After 0 → finalized +# After 1 → finalized +# After swapping with right → not finalized + +# Time complexity: O(N) +# Space Complexity: O(1) \ No newline at end of file diff --git a/problem35.py b/problem35.py new file mode 100644 index 00000000..3aa9d6e8 --- /dev/null +++ b/problem35.py @@ -0,0 +1,84 @@ +from typing import List + +#solution 1: hashing based +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + #hashing based solution + nums.sort() + + result = set() + + for i in range(len(nums)): + if i != 0 and nums[i] == nums[i-1]:#to avoid duplicates iterate till u find next unique + continue + + inner_sum = -nums[i] + seen = set() + for j in range(i+1,len(nums)): + compliment = inner_sum - nums[j] + + if compliment in seen: + triplet = sorted([compliment, nums[j], nums[i]]) #O(3) + result.add(tuple(triplet)) + seen.add(nums[j]) + + return [list(triplet) for triplet in result] + +# You only skip duplicates after a valid triplet +# You never skip a value that could form a new combination, so can't add duplicate check condition for inner j loop. Use sorting here. +# Order guarantees no missed cases + +# Time Complexity: O(nlogn) + O(n2) + O(n) = O(n2) +# space complexity: O(n) + +#Solution 2 : 2 pointer based +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + #2 pointer based solution + nums.sort() + + result = [] + + for i in range(len(nums)): + if i != 0 and nums[i] == nums[i-1]: + continue + if nums[i] > 0: + break #early stopping as we are already sorted the array in asc order so elements after this will always be larger and + #we won't get sum = 0. + + left = i+1 + right = len(nums)-1 + inner_sum = -nums[i] + + while left < right: + if nums[left]+nums[right] == inner_sum: + result.append([nums[i], nums[left], nums[right]]) + left += 1 + right -= 1 + while (left < right and nums[left] == nums[left-1]): + left += 1 + + while (left inner_sum: + right -=1 + while (left int: + + max_area = 0 + + left , right = 0, len(height)-1 + + while left <= right: #it can be left < right also + area = min(height[left], height[right]) * (right-left) + + max_area = max(area, max_area) + + if height[left] < height[right]: + left += 1 + else: + right -=1 + + return max_area + +# Time Complexity: O(N) +# Space Complexity: O(1) +#brute force is nested iterations O(N2) +# The two-pointer approach does not necessarily compute the maximum area for each individual height. +# It still finds the global maximum, because it only evaluates the pairs that could possibly beat the best-so-far. +# example left = 2, right = 8 width = 50 +# min(2,8) * 50 = 2*50 = 100 +# we need to beat this 100. The only way we can beat 100 is to move left pointer, if left pointer is some value say 8 +# then min(8,8)= 8*49 +# if we move right pointer max we can get is min(2,2)*49. which is 2*49 at best we can find. +#Two pointers rely on discarding indices that can’t be part of the global optimum. \ No newline at end of file