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.
Example 1:
1 | Input: nums = [2,7,11,15], target = 9 |
Example 2:
1 | Input: nums = [3,2,4], target = 6 |
Example 3:
1 | Input: nums = [3,3], target = 6 |
Constraints:
- \(2 \leq \text{nums.length} \leq 10^4\)
- \(-10^9 \leq \text{nums[i]} \leq 10^9\)
- \(-10^9 \leq \text{target} \leq 10^9\)
- Only one valid answer exists.
Follow-up: Can you come up with an algorithm that is less than \(O(n^2)\) time complexity?
Approach 1: Brute Force
Algorithm
The brute force approach is simple. Loop through each element \(x\) and find if there is another value that equals to target−\(x\)
Implementation
1 | from __future__ import annotations |
Complexity Analysis
- Time complexity: \(O(n^2)\). For each element, we try to find its complement by looping through the rest of the array which takes \(O(n)\) time. Therefore, the time complexity is \(O(n^2)\).
- Space complexity: \(O(1)\). The space required does not depend on the size of the input array, so only constant space is used.
Notes
1 | from typing import List |
from typing import List imports the List type for type hints. (on Python 3.9+, we can write list[int] and skip this import.)
class Solution: calls code as Solution().twoSum(...). So the function to live inside a class named Solution.
def twoSum(self, nums: List[int], target: int) -> List[int]: defines a method named twoSum.
selfis the instance ofSolution. We don’t use it here; it’s just the method signature.nums: List[int]is a type hint: “numsshould be a list of integers”.target: intmeans “targetshould be an integer”.-> List[int]means “this function returns a list of integers” (the two indices).- Type hints don’t change runtime behavior; they help readers and tools.
Type annotations && method
Here, we provide a detailed explanation of type annotations and methods.
[[leetcode-1-1-two-sum-type-annotation]]
Conventions
instance
As for the instance, it doesn’t have to be named self, but we should name it self (and cls for class methods). That’s the Python convention (PEP 8), and most linters/IDEs expect it. e.g.
1 | from __future__ import annotations |
Notes
§a. from dataclasses import dataclass
dataclassesis a standard library module (a Python file bundled with Python, introduced in 3.7).dataclassis not a class; it’s a function (a decorator) defined inside thedataclassesmodule. We import that function with this line so we can write@dataclassabove a class.
So:
dataclasses→ module (a namespace of things)dataclass→ a decorator function provided by that module
§b. What does @dataclass do? What does @ mean?
@something above a function or class is decorator syntax sugar. This:
1 |
|
is equivalent to:
1 | def f(): ... |
Same for classes:
1 |
|
§c. What @dataclass specifically does
@dataclass takes our class definition and returns a modified class with a bunch of boilerplate auto-generated based on our annotated attributes:
__init__(constructor)__repr__(nice string representation)__eq__(equality by fields)- optional ordering methods (
__lt__, …) if we passorder=True - optional immutability if we pass
frozen=True - slots if we pass
slots=True(Py3.10+)
Example:
1 | from dataclasses import dataclass |
Without @dataclass, we’d have to manually write __init__, __repr__, __eq__, etc.
A slightly fancier variant:
1 | from dataclasses import dataclass |
§d. What does @classmethod do?
Same decorator idea: @classmethod transforms a function defined inside a class into a class method.
- An instance method (normal
def method(self, ...)) receives the instance as its first argument (self). - A class method receives the class as its first argument (
cls) instead—so it can operate on class-level data, construct new instances, or behave polymorphically with subclasses.
Example: alternate constructor
1 | class User: |
Example: class-level state
1 | class Counter: |
§e. When to use which?
- Use
@dataclasswhen we want Python to generate boilerplate methods for a data-holding class. - Use
@classmethodwhen a method should work with the class itself (cls) rather than a specific instance (self)—e.g., alternate constructors or class-wide configuration. - The
@just means “apply this decorator to the thing below.”
decorators
A decorator is just a callable that takes a function and returns a new one, often a wrapper, letting us extend behavior while keeping functions clean and following the Open–Closed Principle.
[[leetcode-1-1-two-sum-type-decorators]]