21. Find the intersection of two integer arrays.
Return the distinct values present in both arrays and explain the complexity of the chosen approach.
I would build a set from the first array, then scan the second array from left to right. For each value, I check whether it exists in the first set. If it does, I add it to a result set called common. The result set removes duplicates automatically. After the scan, I return list(common). The expected time is O(n + m), because Python set operations are O(1) on average. The auxiliary space is O(n + k), commonly reported as O(n).
See the Code while reading this explanation.
The problem asks us to return the distinct integer values that appear in both arrays. We return values, not indices. The output order does not matter. A set-based solution fits well because a set supports fast membership checks and stores each value only once.
- What input sizes, value ranges, and edge cases should the solution handle?
- What output should be returned for empty, invalid, or duplicate input?
- Should I prioritize execution time or memory use, and may I use the standard library?
The function receives two integer arrays named nums1 and nums2.
For the diagram example:
nums1 = [1, 2, 2, 1, 3]
nums2 = [2, 2, 3, 4]
The values that appear in both arrays are 2 and 3. Each value must appear once in the result. One valid returned list is [2, 3]. The order may vary.
First, convert nums1 into a set named values_in_nums1. For the example, it becomes {1, 2, 3}.
This set stores values only. It does not store indices or frequencies. It lets us check whether a value from nums2 appears in nums1 in O(1) time on average.
Create another empty set named common. This set stores the distinct values found in both arrays. Because common is a set, adding the same value more than once keeps only one copy.
The central invariant is this: after processing the first i elements of nums2, common contains exactly the distinct processed values that also appear in nums1.
The initial state is:
values_in_nums1 = {1, 2, 3}
common = {}
Traversal begins at nums2[0]. The values in nums2 are processed from left to right in this order: 2, 2, 3, 4.
Step 1 uses index 0. The current value is 2. common is {} before the check. Since 2 is in values_in_nums1, add 2 to common. common becomes {2}.
Step 2 uses index 1. The current value is 2 again. common is {2} before the check. Since 2 is in values_in_nums1, add it again. A set keeps only one copy, so common remains {2}.
Step 3 uses index 2. The current value is 3. common is {2} before the check. Since 3 is in values_in_nums1, add 3. common becomes {2, 3}.
Step 4 uses index
- The current value is
- common is {2, 3} before the check. Since 4 is not in values_in_nums1, make no change. common remains {2, 3}.
All four values from nums2 have now been processed. The final result set is {2, 3}. One valid returned list is [2, 3].
Before each iteration, common contains exactly the distinct matching values found in the part of nums2 already processed.
If the current value exists in values_in_nums1, it belongs to the intersection, so adding it is correct. If it does not exist in values_in_nums1, it cannot belong to the intersection, so skipping it is correct.
The set common removes repeated matches automatically. Therefore, when the scan finishes, common contains exactly the distinct values present in both arrays.
The code creates values_in_nums1 with set(nums1). It creates common as an empty set.
The for loop reads each value from nums2 in order. The if statement checks whether the current value appears in values_in_nums1. When the condition is true, common.add(value) stores the match.
After the loop, list(common) converts the result set into a list and returns it. The order of that list is not guaranteed, which is allowed by the problem.
Let n be the length of nums1 and m be the length of nums2.
Building set(nums1) takes O(n) time. Scanning nums2 takes O(m) time. Python set lookup and insertion take O(1) time on average. Therefore, the expected total time is O(n + m).
The first set can store up to n distinct values. The result set can store k distinct intersection values. The auxiliary space is O(n + k), commonly reported as O(n) because k cannot be greater than the number of distinct values in nums1.
The method handles duplicate values, negative values, zero, empty arrays, and arrays with no common values.
The key idea is to use one set for fast membership checks and another set for distinct results. values_in_nums1 stores the distinct values from nums1. Then the algorithm scans nums2 from left to right. If a value is in values_in_nums1, it is added to common. The invariant is that after processing the first i elements of nums2, common contains exactly the distinct processed values that also appear in nums1. This avoids the slower nested-loop method that compares every pair of values.
from typing import List
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
# Build a set containing the distinct values from nums1.
# Membership checks in a Python set take O(1) time on average.
values_in_nums1 = set(nums1)
# Store each distinct value that appears in both arrays.
common: set[int] = set()
# Scan nums2 from left to right.
for value in nums2:
# Add the value when it also appears in nums1.
if value in values_in_nums1:
# A set automatically keeps only one copy.
common.add(value)
# Convert the distinct intersection values to a list.
return list(common)
if __name__ == "__main__":
nums1 = [1, 2, 2, 1, 3]
nums2 = [2, 2, 3, 4]
solution = Solution()
result = solution.intersection(nums1, nums2)
# Output order may vary. Sorting is used only for stable display.
print(sorted(result)) # [2, 3]Let n be the number of elements in nums1 and m be the number of elements in nums2. Building values_in_nums1 takes O(n) time. Scanning nums2 takes O(m) time. Python set lookup and insertion take O(1) time on average, so the expected total time is O(n + m). values_in_nums1 uses O(n) extra space. common uses O(k) space, where k is the number of distinct matching values. The total auxiliary space is O(n + k), commonly reported as O(n).
This pattern is useful when software must find shared unique items between two collections. Examples include common user permissions, shared product IDs, matching tags, overlapping feature flags, and duplicate-free matches between datasets. It is especially useful when fast membership checks matter more than preserving the original order.
The interviewer is testing whether you recognize that the problem needs both fast membership checks and duplicate removal. They want to see whether you choose suitable sets, keep values separate from indices, handle repeated values correctly, and maintain a clear invariant. They also evaluate whether your Python code matches your explanation and whether you describe expected hash-set performance and auxiliary space accurately.
A common mistake is storing matches in a list without checking for duplicates. Another mistake is returning indices even though the problem asks for values. Some candidates use nested loops, which can take O(n × m) time. Another mistake is claiming guaranteed O(n + m) time instead of expected O(n + m) time for Python sets. It is also wrong to claim that [2, 3] is the only valid output order.
State the invariant before writing the loop: common contains exactly the distinct processed values from nums2 that also appear in nums1. Then use the example to show how each iteration keeps that invariant true.









