2248. Intersection of Multiple Arrays
Problem Description
In this problem, we are given a 2D array nums
, where each subarray nums[i]
consists of distinct positive integers. The goal is to find all the integers that are common in each of these subarrays and return a sorted list of these common elements. To clarify, an integer is part of the result list if and only if it is present in every subarray of nums
.
For example, if nums = [[4,9,5],[9,4,9,8,4],[4,6,8,9]]
, the integers 4
and 9
are present in all the subarrays, so the sorted result would be [4,9]
.
Intuition
The intuition behind the solution is based on the concept of counting frequency. Since we are looking for integers that are present in all arrays, we can keep a counter for each number to track how many times it appears across all arrays. If a number appears in each subarray, its count should be equal to the number of subarrays in nums
.
Here is the step-by-step approach:
-
Initialize a counter array
cnt
which has a fixed size of1001
to cover the potential range of values innums
subarrays as specified by the problem (assuming the maximum possible integer is1000
). -
Iterate over each subarray in
nums
and then iterate over each integer within that subarray and increment its corresponding count incnt
. -
After counting, iterate through the counter array
cnt
and pick those integers whose counter value is equal to the length ofnums
, which means these integers have appeared in each subarray. -
Collect these common integers and return them in a sorted order. It is implicit that the integers are already in sorted order because we increment the counts while iterating over the fixed range of indices from
1
to1000
. Thus, the resulting list of common integers is inherently sorted. -
The final result is a list of integers that appear in every subarray of
nums
, sorted in ascending order.
The solution effectively reduces the problem to a simple frequency counting mechanism and leverages the fixed range of possible integer values to ensure sorted output.
Solution Approach
The given solution uses a simple counting approach using an array to keep track of the frequency of integers across all subarrays in nums
. Let's break down the implementation into detailed steps:
-
A counter array
cnt
is initialized with1001
elements, all set to0
. This array acts as a hash table to keep track of the frequency of each integer since we know the integers are positive and the constraint hint at a maximum integer value of1000
. -
The outer
for
loop iterates through each subarrayarr
within the main arraynums
. For each subarray, we iterate through its elements using the innerfor
loop. -
Inside the inner
for
loop, we use the integerx
from the subarray as an index to increment the counter at that index incnt
array by1
. This step counts the occurrence of each integer across all subarrays.for arr in nums: for x in arr: cnt[x] += 1
-
After filling the
cnt
array with counts, a list comprehension is used to iterate over all possible integers (usingenumerate(cnt)
which gives us both the numberx
and its countv
), checking if the countv
is equal to the length ofnums
. This ensures that we only select integers that are present in all subarrays.return [x for x, v in enumerate(cnt) if v == len(nums)]
-
The list comprehension also takes care of assembling the output list and the nature of enumeration guarantees the order will be ascending, hence satisfying the problem requirements of returning the common elements in sorted order.
The data structures utilized here are:
- An array (
cnt
) used as a frequency counter. - A list comprehension to generate the output list.
The algorithm is a well-known counting sort technique which is very efficient when the range of potential values is known and reasonably small, as it is in this case. As a result, the complexity of this solution is very good, with time complexity being O(N * M)
where N
is the number of subarrays and M
is the average length of these subarrays, and space complexity is O(1)
since the size of the cnt
array is fixed and does not grow with the input size.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Suppose we have the following 2D array:
nums = [[1, 2, 3], [2, 3, 4], [3, 4, 5, 6]]
The aim is to find all numbers that appear in every subarray.
-
Initialize a counter array
cnt
with size1001
, all elements set to0
. -
We go through each subarray
arr
innums
. For the first subarray[1, 2, 3]
, we incrementcnt[1]
,cnt[2]
, andcnt[3]
by1
. After processing the first subarray,cnt
looks like this:cnt = [..., 0, 1, 1, 1, 0, 0, ...] (positions 1, 2, and 3 are incremented)
-
Repeat step 2 for the second subarray
[2, 3, 4]
. Now,cnt[2]
,cnt[3]
, andcnt[4]
are incremented by1
, resulting in:cnt = [..., 0, 1, 2, 2, 1, 0, ...] (positions 2, 3, and 4 are incremented)
-
Do the same for the third subarray
[3, 4, 5, 6]
, incrementingcnt[3]
,cnt[4]
,cnt[5]
, andcnt[6]
. After this step,cnt
is:cnt = [..., 0, 1, 2, 3, 2, 1, 1, 0, ...] (positions 3, 4, 5, and 6 are incremented)
-
After processing all subarrays, we iterate through the counter array
cnt
and look for values that are equal to the length ofnums
(which is3
in this case). We find thatcnt[3]
is3
. -
The final output list will only include the number
3
as it is the only number whose count is equal to the number of subarrays innums
. We return[3]
.
The solution code that accomplishes this is:
cnt = [0] * 1001
for arr in nums:
for x in arr:
cnt[x] += 1
return [x for x, v in enumerate(cnt) if v == len(nums)]
And our example will yield the output:
[3]
This simple example demonstrates how the counting approach finds common elements present in all subarrays reliably and efficiently.
Solution Implementation
1from typing import List
2
3class Solution:
4 def intersection(self, nums: List[List[int]]) -> List[int]:
5 # Initialize a list to count the occurrences of each number, assuming numbers range from 0 to 1000.
6 # This means each index represents a number, and the value at that index represents its count.
7 count = [0] * 1001
8
9 # Loop through each list in the list of lists `nums`.
10 for num_list in nums:
11 # Using a set to avoid counting duplicates in the same list.
12 unique_nums = set(num_list)
13 # Increment the count for each number found in the list.
14 for num in unique_nums:
15 count[num] += 1
16
17 # Return a list of numbers (index) where the count is equal to the length of `nums`
18 # i.e., the number appeared in all lists.
19 return [num for num, frequency in enumerate(count) if frequency == len(nums)]
20
1import java.util.ArrayList;
2import java.util.List;
3
4class Solution {
5 public List<Integer> intersection(int[][] arrays) {
6 // Array to store the count of each element (assuming the range of elements is 0-1000)
7 int[] count = new int[1001];
8
9 // Iterate through each sub-array
10 for (int[] array : arrays) {
11 // Count each element in the sub-array
12 for (int element : array) {
13 ++count[element];
14 }
15 }
16
17 // List to store the result (elements present in all sub-arrays)
18 List<Integer> result = new ArrayList<>();
19
20 // Iterate through the count array to find elements with a count equal to the number of arrays,
21 // which means they appear in every sub-array.
22 for (int i = 0; i < 1001; ++i) {
23 if (count[i] == arrays.length) {
24 result.add(i); // Add to the result list if element is present in all arrays
25 }
26 }
27
28 // Return the result list
29 return result;
30 }
31}
32
1#include <vector> // Include the required header for the vector container.
2
3class Solution {
4public:
5 // The function 'intersection' takes a vector of vector of ints as input.
6 // It returns a vector of integers that are common in all inner vectors.
7 vector<int> intersection(vector<vector<int>>& nums) {
8 // We use an array to keep count of integer occurrences across all inner vectors.
9 int countArray[1001] = {}; // There are 1001 elements initialized to 0.
10
11 // Iterate over the outer vector 'nums', which contains inner vectors.
12 for (auto& innerArray : nums) {
13 // For each integer in the inner vectors, increment its count in 'countArray'.
14 for (int num : innerArray) {
15 countArray[num]++;
16 }
17 }
18
19 // Define a vector to hold the intersection results.
20 vector<int> intersectionResult;
21
22 // Iterate over the 'countArray' to check which numbers have a count
23 // equal to the size of the outer vector (i.e., they appear in all inner vectors).
24 for (int i = 0; i < 1001; ++i) {
25 if (countArray[i] == nums.size()) {
26 intersectionResult.push_back(i); // Add the number to the result vector.
27 }
28 }
29
30 // Return the resulting intersection vector.
31 return intersectionResult;
32 }
33};
34
1function intersection(nums: number[][]): number[] {
2 // Create an array to keep track of the count of each number across all subarrays
3 const count = new Array(1001).fill(0);
4
5 // Iterate over each subarray in nums
6 for (const subArray of nums) {
7 // Iterate over each number in the subarray
8 for (const num of subArray) {
9 // Increment the count for this number
10 count[num]++;
11 }
12 }
13
14 // Prepare an array to hold the numbers present in all subarrays
15 const result: number[] = [];
16
17 // Iterate over the possible numbers
18 for (let i = 0; i < 1001; i++) {
19 // If the count of a number is equal to the length of nums,
20 // it means the number is present in all subarrays
21 if (count[i] === nums.length) {
22 result.push(i);
23 }
24 }
25
26 // Return the result array containing the intersection
27 return result;
28}
29
Time and Space Complexity
The time complexity of the provided code is O(n * k + m)
, where n
represents the number of arrays in nums
, k
is the average length of the arrays in nums
, and m
is the fixed size of counting array cnt
(1001 in this case). The first term n * k
comes from the nested loops where we iterate over all elements across all the arrays. The second term m
is due to the list comprehension at the end, which iterates over the whole cnt
array once.
The space complexity of the code is O(m)
. This is because we use a fixed-size array cnt
to count occurrences of each number (between 0 and 1000, inclusively). Space complexity does not depend on the input size, only on the size of the counting array cnt
.
Learn more about how to find time and space complexity quickly using problem constraints.
Which technique can we use to find the middle of a linked list?
Recommended Readings
LeetCode 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 we
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 algomonster s3 us east 2 amazonaws com recursion jpg You first
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!