2956. Find Common Elements Between Two Arrays
Problem Description
You are given two integer arrays nums1
and nums2
with sizes n
and m
respectively.
Your task is to calculate two values:
-
answer1
: Count how many indicesi
innums1
have the property thatnums1[i]
exists somewhere innums2
. In other words, for each element at positioni
innums1
, check if that element appears anywhere innums2
. Count all such positions. -
answer2
: Count how many indicesi
innums2
have the property thatnums2[i]
exists somewhere innums1
. In other words, for each element at positioni
innums2
, check if that element appears anywhere innums1
. Count all such positions.
Return these two counts as an array [answer1, answer2]
.
For example, if nums1 = [2, 3, 2]
and nums2 = [1, 2]
:
- For
answer1
: We check each element innums1
nums1[0] = 2
exists innums2
, so we count itnums1[1] = 3
does not exist innums2
, so we don't count itnums1[2] = 2
exists innums2
, so we count it- Therefore,
answer1 = 2
- For
answer2
: We check each element innums2
nums2[0] = 1
does not exist innums1
, so we don't count itnums2[1] = 2
exists innums1
, so we count it- Therefore,
answer2 = 1
- The result would be
[2, 1]
Intuition
The key insight is that we need to efficiently check membership - whether an element from one array exists in another array. When we need to repeatedly check if elements exist in a collection, using a hash set is the natural choice because it provides O(1)
lookup time.
Think about the naive approach first: for each element in nums1
, we'd need to scan through all of nums2
to check if it exists there. This would take O(n * m)
time. Similarly for checking elements from nums2
in nums1
.
However, if we first convert both arrays into sets, we can transform this into a much more efficient solution. Sets automatically handle duplicates and give us constant-time membership checking.
Once we have s1 = set(nums1)
and s2 = set(nums2)
, the problem becomes straightforward:
- For each element
x
in the originalnums1
array, check ifx in s2
(constant time) - For each element
x
in the originalnums2
array, check ifx in s1
(constant time)
The beauty of this approach is that even though we iterate through the original arrays (not the sets), we're using the sets purely for fast membership testing. This preserves the count of duplicate elements in the original arrays while leveraging the speed of set operations.
The solution elegantly uses Python's generator expressions with sum()
to count the matching elements in a single line for each array, making the code both efficient and concise.
Solution Approach
The implementation follows a straightforward approach using hash tables (sets) for efficient membership checking.
Step 1: Create Sets from Arrays
First, we convert both input arrays into sets:
s1, s2 = set(nums1), set(nums2)
This transformation allows us to perform O(1)
membership checks. The sets s1
and s2
contain the unique elements from nums1
and nums2
respectively.
Step 2: Count Matching Elements
We need to count elements at each index of the original arrays that exist in the opposite set:
For answer1
, we iterate through each element x
in the original nums1
array and check if it exists in s2
:
sum(x in s2 for x in nums1)
This generator expression checks each element and produces True
(counted as 1) or False
(counted as 0), then sums up all the 1s.
For answer2
, we do the same but iterate through nums2
and check against s1
:
sum(x in s1 for x in nums2)
Step 3: Return Results
Both counts are computed and returned as a list:
return [sum(x in s2 for x in nums1), sum(x in s1 for x in nums2)]
Time Complexity: O(n + m)
where n
and m
are the lengths of nums1
and nums2
. Creating the sets takes O(n + m)
time, and checking membership for all elements also takes O(n + m)
time.
Space Complexity: O(n + m)
for storing the two sets containing unique elements from both arrays.
The solution efficiently handles duplicate elements in the original arrays - each occurrence is counted separately in the final answer, even though the sets only store unique values.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with a concrete example:
Given: nums1 = [4, 3, 2, 3, 1]
and nums2 = [2, 2, 5, 2, 3, 6]
Step 1: Create Sets
- Convert
nums1
to set:s1 = {1, 2, 3, 4}
- Convert
nums2
to set:s2 = {2, 3, 5, 6}
Step 2: Calculate answer1
Count how many elements in nums1
exist in s2
:
nums1[0] = 4
: Is4
ins2
? No (4 not in {2, 3, 5, 6}) → count: 0nums1[1] = 3
: Is3
ins2
? Yes (3 is in {2, 3, 5, 6}) → count: 1nums1[2] = 2
: Is2
ins2
? Yes (2 is in {2, 3, 5, 6}) → count: 2nums1[3] = 3
: Is3
ins2
? Yes (3 is in {2, 3, 5, 6}) → count: 3nums1[4] = 1
: Is1
ins2
? No (1 not in {2, 3, 5, 6}) → count: 3
answer1 = 3
Step 3: Calculate answer2
Count how many elements in nums2
exist in s1
:
nums2[0] = 2
: Is2
ins1
? Yes (2 is in {1, 2, 3, 4}) → count: 1nums2[1] = 2
: Is2
ins1
? Yes (2 is in {1, 2, 3, 4}) → count: 2nums2[2] = 5
: Is5
ins1
? No (5 not in {1, 2, 3, 4}) → count: 2nums2[3] = 2
: Is2
ins1
? Yes (2 is in {1, 2, 3, 4}) → count: 3nums2[4] = 3
: Is3
ins1
? Yes (3 is in {1, 2, 3, 4}) → count: 4nums2[5] = 6
: Is6
ins1
? No (6 not in {1, 2, 3, 4}) → count: 4
answer2 = 4
Result: [3, 4]
Note how duplicate values (like the multiple 3s in nums1
and multiple 2s in nums2
) are each counted individually when they exist in the opposite set, even though the sets themselves only store unique values.
Solution Implementation
1class Solution:
2 def findIntersectionValues(self, nums1: List[int], nums2: List[int]) -> List[int]:
3 # Convert both lists to sets for O(1) lookup time
4 set1 = set(nums1)
5 set2 = set(nums2)
6
7 # Count elements in nums1 that exist in set2
8 count1 = sum(1 for num in nums1 if num in set2)
9
10 # Count elements in nums2 that exist in set1
11 count2 = sum(1 for num in nums2 if num in set1)
12
13 # Return both counts as a list
14 return [count1, count2]
15
1class Solution {
2 public int[] findIntersectionValues(int[] nums1, int[] nums2) {
3 // Create boolean arrays to mark presence of elements (0-100 range)
4 // Using size 101 to accommodate values from 0 to 100
5 int[] existsInNums1 = new int[101];
6 int[] existsInNums2 = new int[101];
7
8 // Mark elements present in nums1
9 for (int num : nums1) {
10 existsInNums1[num] = 1;
11 }
12
13 // Mark elements present in nums2
14 for (int num : nums2) {
15 existsInNums2[num] = 1;
16 }
17
18 // Initialize result array
19 // result[0]: count of elements in nums1 that appear in nums2
20 // result[1]: count of elements in nums2 that appear in nums1
21 int[] result = new int[2];
22
23 // Count elements from nums1 that exist in nums2
24 for (int num : nums1) {
25 result[0] += existsInNums2[num];
26 }
27
28 // Count elements from nums2 that exist in nums1
29 for (int num : nums2) {
30 result[1] += existsInNums1[num];
31 }
32
33 return result;
34 }
35}
36
1class Solution {
2public:
3 vector<int> findIntersectionValues(vector<int>& nums1, vector<int>& nums2) {
4 // Arrays to mark presence of elements (0-100 range based on constraints)
5 // exists_in_nums1[i] = 1 if i exists in nums1, 0 otherwise
6 int exists_in_nums1[101] = {};
7 int exists_in_nums2[101] = {};
8
9 // Mark all elements present in nums1
10 for (int& num : nums1) {
11 exists_in_nums1[num] = 1;
12 }
13
14 // Mark all elements present in nums2
15 for (int& num : nums2) {
16 exists_in_nums2[num] = 1;
17 }
18
19 // Result vector: [count1, count2]
20 // count1: number of indices in nums1 where nums1[i] exists in nums2
21 // count2: number of indices in nums2 where nums2[i] exists in nums1
22 vector<int> result(2);
23
24 // Count elements in nums1 that exist in nums2
25 for (int& num : nums1) {
26 result[0] += exists_in_nums2[num];
27 }
28
29 // Count elements in nums2 that exist in nums1
30 for (int& num : nums2) {
31 result[1] += exists_in_nums1[num];
32 }
33
34 return result;
35 }
36};
37
1/**
2 * Finds the count of elements in each array that exist in the other array
3 * @param nums1 - First array of numbers
4 * @param nums2 - Second array of numbers
5 * @returns Array with two values: [count of nums1 elements in nums2, count of nums2 elements in nums1]
6 */
7function findIntersectionValues(nums1: number[], nums2: number[]): number[] {
8 // Create frequency arrays to mark presence of elements (0-100 range)
9 // Using arrays as hash sets for O(1) lookup
10 const presenceInNums1: number[] = Array(101).fill(0);
11 const presenceInNums2: number[] = Array(101).fill(0);
12
13 // Mark elements present in nums1
14 for (const num of nums1) {
15 presenceInNums1[num] = 1;
16 }
17
18 // Mark elements present in nums2
19 for (const num of nums2) {
20 presenceInNums2[num] = 1;
21 }
22
23 // Initialize result array with two counters
24 const result: number[] = Array(2).fill(0);
25
26 // Count how many elements from nums1 exist in nums2
27 for (const num of nums1) {
28 result[0] += presenceInNums2[num];
29 }
30
31 // Count how many elements from nums2 exist in nums1
32 for (const num of nums2) {
33 result[1] += presenceInNums1[num];
34 }
35
36 return result;
37}
38
Time and Space Complexity
Time Complexity: O(n + m)
- Creating
set(nums1)
takesO(n)
time wheren
is the length ofnums1
- Creating
set(nums2)
takesO(m)
time wherem
is the length ofnums2
- The first sum comprehension
sum(x in s2 for x in nums1)
iterates through alln
elements innums1
, and each set membership checkx in s2
takesO(1)
average time, resulting inO(n)
total time - The second sum comprehension
sum(x in s1 for x in nums2)
iterates through allm
elements innums2
, and each set membership checkx in s1
takesO(1)
average time, resulting inO(m)
total time - Overall time complexity:
O(n) + O(m) + O(n) + O(m) = O(n + m)
Space Complexity: O(n + m)
- Set
s1
stores unique elements fromnums1
, which in the worst case contains alln
elements, requiringO(n)
space - Set
s2
stores unique elements fromnums2
, which in the worst case contains allm
elements, requiringO(m)
space - The generator expressions in the sum functions use
O(1)
additional space - Overall space complexity:
O(n) + O(m) = O(n + m)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Confusing Set Intersection with Index Counting
The Mistake: A common error is misunderstanding the problem and calculating the intersection of two sets instead of counting individual occurrences:
# WRONG approach
def findIntersectionValues(self, nums1: List[int], nums2: List[int]) -> List[int]:
set1 = set(nums1)
set2 = set(nums2)
# This counts unique elements, not occurrences!
intersection = set1 & set2
return [len(intersection), len(intersection)] # Incorrect!
Why It's Wrong:
The problem asks for the count of indices where elements exist in the other array, not the count of unique common elements. If nums1 = [2, 3, 2]
and nums2 = [1, 2]
, the intersection approach would incorrectly return [1, 1]
instead of [2, 1]
.
The Fix: Count each occurrence separately by iterating through the original arrays:
# CORRECT approach
count1 = sum(1 for num in nums1 if num in set2)
count2 = sum(1 for num in nums2 if num in set1)
Pitfall 2: Creating Sets from Wrong Arrays
The Mistake: Creating sets from the same array you're iterating through:
# WRONG - checking if nums1 elements exist in nums1's set
count1 = sum(1 for num in nums1 if num in set1) # Should be set2!
count2 = sum(1 for num in nums2 if num in set2) # Should be set1!
Why It's Wrong:
This would always count all elements since every element obviously exists in its own set, giving incorrect results like [len(nums1), len(nums2)]
.
The Fix: Ensure you're checking against the opposite array's set:
# Check nums1 elements against set2, and nums2 elements against set1
count1 = sum(1 for num in nums1 if num in set2)
count2 = sum(1 for num in nums2 if num in set1)
Pitfall 3: Not Handling Duplicates Correctly
The Mistake: Trying to optimize by removing duplicates from the original arrays before counting:
# WRONG - removing duplicates changes the count
unique_nums1 = list(set(nums1))
unique_nums2 = list(set(nums2))
count1 = sum(1 for num in unique_nums1 if num in set2)
Why It's Wrong:
The problem specifically wants to count each index/occurrence. If nums1 = [2, 2, 2]
and nums2 = [2]
, the answer should be [3, 1]
, not [1, 1]
.
The Fix: Iterate through the original arrays with all their duplicates intact, only use sets for membership checking:
# Keep original arrays for iteration, use sets only for lookup
set1 = set(nums1)
set2 = set(nums2)
count1 = sum(1 for num in nums1 if num in set2) # nums1, not set1
Depth first search is equivalent to which of the tree traversal order?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!