118 lines
4.4 KiB
YAML
118 lines
4.4 KiB
YAML
title: Two Sum
|
|
slug: two-sum
|
|
difficulty: easy
|
|
leetcode_id: 1
|
|
leetcode_url: https://leetcode.com/problems/two-sum/
|
|
categories:
|
|
- arrays
|
|
- hash-tables
|
|
patterns:
|
|
- two-pointers
|
|
|
|
description: |
|
|
Given an array of integers `nums` and an integer `target`, return indices of the two numbers such that they add up to `target`.
|
|
|
|
You may assume that each input would have exactly one solution, and you may not use the same element twice.
|
|
|
|
You can return the answer in any order.
|
|
|
|
constraints: |
|
|
- 2 <= nums.length <= 10^4
|
|
- -10^9 <= nums[i] <= 10^9
|
|
- -10^9 <= target <= 10^9
|
|
- Only one valid answer exists.
|
|
|
|
examples:
|
|
- input: "nums = [2,7,11,15], target = 9"
|
|
output: "[0,1]"
|
|
explanation: "Because nums[0] + nums[1] == 9, we return [0, 1]."
|
|
- input: "nums = [3,2,4], target = 6"
|
|
output: "[1,2]"
|
|
explanation: "Because nums[1] + nums[2] == 6, we return [1, 2]."
|
|
- input: "nums = [3,3], target = 6"
|
|
output: "[0,1]"
|
|
explanation: "Because nums[0] + nums[1] == 6, we return [0, 1]."
|
|
|
|
explanation:
|
|
approach: |
|
|
1. Create a hash map to store each number and its index as we iterate
|
|
2. For each number, calculate its complement (target - current number)
|
|
3. Check if the complement exists in the hash map
|
|
4. If found, return the current index and the complement's index
|
|
5. If not found, add the current number and its index to the hash map
|
|
6. Continue until a pair is found
|
|
|
|
intuition: |
|
|
The brute force approach would check every pair of numbers, resulting in O(n²) time.
|
|
Instead, we can use a hash map to achieve O(n) time by trading space for speed.
|
|
|
|
The key insight is that for each number x, we're looking for (target - x). Rather than
|
|
scanning the entire array each time, we store seen numbers in a hash map for O(1) lookup.
|
|
|
|
We build the hash map as we go, which elegantly handles the constraint of not using
|
|
the same element twice — when we check for a complement, it can only be a previously
|
|
seen element.
|
|
|
|
common_pitfalls:
|
|
- title: Using the same element twice
|
|
description: |
|
|
Checking if complement exists before adding current element to the map prevents
|
|
using the same index twice. If you add first then check, you might match an
|
|
element with itself.
|
|
wrong_approach: "Adding to map before checking complement"
|
|
correct_approach: "Check complement first, then add to map"
|
|
|
|
- title: Returning values instead of indices
|
|
description: |
|
|
The problem asks for indices, not the actual values. Make sure you store and
|
|
return the indices from the hash map.
|
|
wrong_approach: "return [num, complement]"
|
|
correct_approach: "return [seen[complement], i]"
|
|
|
|
- title: Forgetting duplicate values
|
|
description: |
|
|
When there are duplicate values (e.g., [3,3] with target 6), the algorithm
|
|
still works because we check for complement before adding to the map.
|
|
|
|
key_takeaways:
|
|
- Hash maps trade space for time, turning O(n) lookups into O(1)
|
|
- Building data structures incrementally can prevent edge cases
|
|
- Always clarify whether to return indices or values
|
|
- This pattern appears in many "find pair" problems
|
|
|
|
time_complexity: "O(n)"
|
|
space_complexity: "O(n)"
|
|
complexity_explanation: |
|
|
Time: We iterate through the array once, and each hash map operation is O(1) average.
|
|
Space: In the worst case, we store all n elements in the hash map before finding a match.
|
|
|
|
solutions:
|
|
- approach_name: Hash Map (Optimal)
|
|
is_optimal: true
|
|
code: |
|
|
def two_sum(nums: list[int], target: int) -> list[int]:
|
|
seen = {}
|
|
for i, num in enumerate(nums):
|
|
complement = target - num
|
|
if complement in seen:
|
|
return [seen[complement], i]
|
|
seen[num] = i
|
|
return [] # No solution found
|
|
explanation: |
|
|
Single pass through the array, storing each number's index.
|
|
For each number, check if its complement exists in the map.
|
|
|
|
- approach_name: Brute Force
|
|
is_optimal: false
|
|
code: |
|
|
def two_sum(nums: list[int], target: int) -> list[int]:
|
|
n = len(nums)
|
|
for i in range(n):
|
|
for j in range(i + 1, n):
|
|
if nums[i] + nums[j] == target:
|
|
return [i, j]
|
|
return []
|
|
explanation: |
|
|
Check every pair of numbers. Simple but inefficient for large inputs.
|
|
Time: O(n²), Space: O(1).
|