454. 4Sum II
Using brutal force, we can do 4 iterations for each of the nums and count all the pairs giving a sum of 0. However, a better way to reduce the time complexity from N^4 to N^2 is, to log all the pairs of adding sum from nums 1 and nums 2. Then iterate through nums 3 and 4 and check if 0 - (nums 3 + nums 4) exists in the table. If so, add up the number of occurrences. Time complexity = N(n^4)
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
length = len(nums1)
result = dict()
count = 0
for i in range(length):
for j in range(length):
key = nums1[i] + nums2[j]
if key not in result.keys():
result[key] = 1
else:
result[key] += 1
for i in range(length):
for j in range(length):
key = 0 - (nums3[i] + nums4[j])
if key in result.keys():
count += result[key]
return count
383. Ransom Note
We can use either dict (map) or array to solve this problem. array mighrt be better because 26 letters are finite and an array will save some time in operations. so we convert the letters of magazine to a table to mark the occurrence. then we subtract all the occurrences from ransomNote. if a letter is not marked, then False. Else, it must be True. Time complexity should be N(n)
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
count_table = [0]*26
for i in magazine:
count_table[ord(i) - ord('a')] += 1
for i in ransomNote:
if count_table[ord(i) - ord('a')] == 0:
return False
else:
count_table[ord(i) - ord('a')] -= 1
return True
15. 3Sum
0. sort the array
1. fix a and then use two pointers to find sum == 0 from front and back
2. remove duplicates from a,b,and c. the adjacent next value cannot be the same
Attention:
i,left,right are index not value.
To remove duplicates from a, nums[a] != nums[a-1] (a>0) so at least we can log a value before we move on. Nonetheless, for b and c, nums[b= != nums[b+1] we can skip the next value because we already logged the previous value. Time complexity N(n^2)
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
ans = []
nums.sort()
print(nums)
for i in range(len(nums)):
left = i+1
right = len(nums) - 1
if i > 0 and nums[i] == nums[i-1]: # remove duplicate from a
continue
while(left < right):
total = nums[i] + nums[left] + nums[right]
if total < 0:
left = left + 1
elif total > 0:
right = right - 1
else:
ans.append([nums[i],nums[left],nums[right]])
while left < right and nums[left] == nums[left+1]: left = left + 1 # remove duplicates from b
while left < right and nums[right] == nums[right-1]: right = right - 1 # remove duplicates from c
left = left + 1
right = right - 1
return ans
18. 4Sum
add one more layer out of 3sum. the second iterator should ski[p when j > i+1, because we want to skip the first index for every i loop.
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
res = []
n = len(nums)
print(nums)
for i in range(n):
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, n):
if j > i + 1 and nums[j] == nums[j-1]:
continue
left = j + 1
right = n - 1
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total > target:
right -= 1
elif total < target:
left += 1
else:
res.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]: left += 1
while left < right and nums[right] == nums[right - 1]: right -= 1
left += 1
right -= 1
return res