Grind 75 Questions - 1 - Two Sum
Senthil E.
Gen AI/ML Engineer/LLMOps | Databricks 5x Certified, Google 3x Certified, Tensorflow and AWS ML Certified.
Introduction:
Based on the "Grind 75", I will solve the 75 different problems on LeetCode, all using Python. I will follow the below format for all problems.
The Grind75 is
The first problem is Two Sum. Let's dive in.
Two Sum:
2. Edge Cases:
?? What if the array is empty?
?? What if the array only has one element?
?? What if the array has duplicate elements that sum up to the target?
3. Available Approaches:
Brute Force Approach:
You can use two loops. In the outer loop, take one element, and in the inner loop, check for the other number, which, when added to the first one, equals the target.
def two_sum(nums, target):
? ? # Loop through each number in the list.
? ? for i in range(len(nums)):
? ? ? ? # Loop through the rest of the numbers in the list.
? ? ? ? for j in range(i + 1, len(nums)):
? ? ? ? ? ? # If these two numbers add up to the target,
? ? ? ? ? ? if nums[i] + nums[j] == target:
? ? ? ? ? ? ? ? # return their indices.
? ? ? ? ? ? ? ? return [i, j]
? ? # If no two numbers sum up to the target, return an empty list.
? ? return []
In this code, we start with the first number (nums[i]), then check every other number in the list (nums[j]) to see if they add up to the target. If they do, we return their indices. If we've checked all pairs of numbers and haven't found a pair that adds up to the target, we return an empty list.
Note that this approach has a time complexity of O(n^2), where n is the number of elements in the list, because for each element in the list, we're checking every other element. This is less efficient than the dictionary-based approach, which only needs to check each element once, resulting in a time complexity of O(n). However, the brute force approach is simpler and doesn't require any additional space, which could make it a reasonable choice for smaller inputs.
领英推荐
Hashing (Efficient Approach):
You can use a dictionary to store the number as a key and its index as a value. Then for each number, you check if its complement (target - number) exists in the dictionary or not. If it does, return the indices.
def two_sum(nums, target):
? ? num_map = {}? # Create a dictionary to store the numbers and their indices.
? ??
? ? # Iterate through the list of numbers.
? ? for i, num in enumerate(nums):
? ? ? ? # Calculate the complement of the current number.
? ? ? ? complement = target - num
? ? ? ? # If the complement exists in our map, return the index of the complement and the current index.
? ? ? ? if complement in num_map:
? ? ? ? ? ? return [num_map[complement], i]
? ? ? ? # If the complement does not exist in our map, add the current number and its index to the map.
? ? ? ? num_map[num] = i
? ? # If no two numbers sum up to the target, return an empty list.
? ? return []
Logic Explanation:
Code Explanation:
Pattern:
The pattern in this problem is that for each number in the list, we are trying to find its complement in the rest of the list. If we find it, we know that these two numbers add up to the target. By storing the numbers and their indices in a dictionary, we can quickly look up the complement. This is a typical pattern in problems where we need to find pairs of elements that satisfy some condition. It shows the power of the dictionary data structure for lookup operations.
Big O Notation Explanation:
For the given problem, the time complexity of our solution is O(n), where n is the size of the input list. This means that in the worst-case scenario, our algorithm will perform a number of operations that is proportional to the size of the list. This is because we iterate over the list just once, performing constant time operations for each element.
The space complexity of the algorithm is also O(n), as in the worst-case, we might end up storing every element of the list in the dictionary.
Points to Remember:
Testing with sample data:
nums = [2, 7, 11, 15], target = 9
If we didn't find any two numbers that add up to the target after going through the entire list, we would return an empty list [].
This solution is faster than the brute force approach because we're only going through the list once; hence it has a time complexity of O(n). We're using a dictionary to remember the numbers we've seen and where we saw them, which makes checking if we've seen a number before very fast (in constant time, O(1)).
The next problem will be Valid Parentheses(Stacks).