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 indicesiinnums1have the property thatnums1[i]exists somewhere innums2. In other words, for each element at positioniinnums1, check if that element appears anywhere innums2. Count all such positions. -
answer2: Count how many indicesiinnums2have the property thatnums2[i]exists somewhere innums1. In other words, for each element at positioniinnums2, 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 innums1nums1[0] = 2exists innums2, so we count itnums1[1] = 3does not exist innums2, so we don't count itnums1[2] = 2exists innums2, so we count it- Therefore,
answer1 = 2
- For
answer2: We check each element innums2nums2[0] = 1does not exist innums1, so we don't count itnums2[1] = 2exists 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
xin the originalnums1array, check ifx in s2(constant time) - For each element
xin the originalnums2array, 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
nums1to set:s1 = {1, 2, 3, 4} - Convert
nums2to set:s2 = {2, 3, 5, 6}
Step 2: Calculate answer1
Count how many elements in nums1 exist in s2:
nums1[0] = 4: Is4ins2? No (4 not in {2, 3, 5, 6}) → count: 0nums1[1] = 3: Is3ins2? Yes (3 is in {2, 3, 5, 6}) → count: 1nums1[2] = 2: Is2ins2? Yes (2 is in {2, 3, 5, 6}) → count: 2nums1[3] = 3: Is3ins2? Yes (3 is in {2, 3, 5, 6}) → count: 3nums1[4] = 1: Is1ins2? 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: Is2ins1? Yes (2 is in {1, 2, 3, 4}) → count: 1nums2[1] = 2: Is2ins1? Yes (2 is in {1, 2, 3, 4}) → count: 2nums2[2] = 5: Is5ins1? No (5 not in {1, 2, 3, 4}) → count: 2nums2[3] = 2: Is2ins1? Yes (2 is in {1, 2, 3, 4}) → count: 3nums2[4] = 3: Is3ins1? Yes (3 is in {1, 2, 3, 4}) → count: 4nums2[5] = 6: Is6ins1? 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]
151class 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}
361class 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};
371/**
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}
38Time and Space Complexity
Time Complexity: O(n + m)
- Creating
set(nums1)takesO(n)time wherenis the length ofnums1 - Creating
set(nums2)takesO(m)time wheremis the length ofnums2 - The first sum comprehension
sum(x in s2 for x in nums1)iterates through allnelements innums1, and each set membership checkx in s2takesO(1)average time, resulting inO(n)total time - The second sum comprehension
sum(x in s1 for x in nums2)iterates through allmelements innums2, and each set membership checkx in s1takesO(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
s1stores unique elements fromnums1, which in the worst case contains allnelements, requiringO(n)space - Set
s2stores unique elements fromnums2, which in the worst case contains allmelements, 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
Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted 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!