2540. Minimum Common Value
Problem Description
You are given two integer arrays nums1
and nums2
that are already sorted in non-decreasing order. Your task is to find the smallest integer that appears in both arrays.
The key requirements are:
- Both arrays are sorted in non-decreasing order (smallest to largest)
- Find the minimum integer that exists in both arrays
- An integer is considered "common" if it appears at least once in each array
- If no integer appears in both arrays, return
-1
For example:
- If
nums1 = [1, 2, 3]
andnums2 = [2, 4]
, the common integer is2
, so return2
- If
nums1 = [1, 2, 3, 6]
andnums2 = [2, 3, 4, 5]
, both2
and3
are common, but2
is smaller, so return2
- If
nums1 = [1, 3, 5]
andnums2 = [2, 4, 6]
, there are no common integers, so return-1
The solution uses a two-pointer technique to efficiently find the minimum common element. Starting from the beginning of both arrays (since they're sorted), it compares elements at positions i
and j
. When nums1[i] == nums2[j]
, that's the minimum common element (due to sorted order). When nums1[i] < nums2[j]
, pointer i
advances since the current element in nums1
cannot exist in nums2
at or after position j
. Similarly, when nums1[i] > nums2[j]
, pointer j
advances. This continues until either a common element is found or one array is fully traversed.
Intuition
Since both arrays are sorted in non-decreasing order, we can leverage this property to find the common element efficiently. Think about it this way: if we're looking for the minimum common element, and both arrays are sorted, then the first common element we encounter while traversing from the beginning will automatically be the minimum.
The key insight is that we don't need to check every element in nums1
against every element in nums2
(which would take O(m*n)
time). Instead, we can use two pointers moving through the arrays simultaneously.
Why does this work? Consider what happens when we compare two elements:
- If
nums1[i] == nums2[j]
, we've found a common element, and since we're traversing from the smallest values, this must be the minimum common element. - If
nums1[i] < nums2[j]
, the current element innums1
is too small to exist innums2
at positionj
or beyond (sincenums2
is sorted). So we need to move to a larger element innums1
by incrementingi
. - If
nums1[i] > nums2[j]
, similarly, the current element innums2
is too small to match anything at positioni
or beyond innums1
, so we incrementj
.
This approach essentially "synchronizes" our traversal through both arrays, skipping elements that cannot possibly be common. We're always moving the pointer that points to the smaller element, gradually bringing both pointers toward potential matches. This guarantees we'll find the minimum common element if it exists, or exhaust at least one array if no common element exists.
The beauty of this solution is that it only requires one pass through the arrays with time complexity O(m + n)
instead of the brute force O(m*n)
.
Learn more about Two Pointers and Binary Search patterns.
Solution Approach
The solution implements the two-pointer technique to efficiently find the minimum common element between two sorted arrays.
Implementation Details:
-
Initialize Two Pointers: Start with
i = 0
fornums1
andj = 0
fornums2
. Also store the lengths of both arrays asm = len(nums1)
andn = len(nums2)
. -
Traverse Both Arrays Simultaneously: Use a while loop that continues as long as both pointers are within their respective array bounds:
while i < m and j < n
. -
Compare Elements at Current Positions:
-
Equal elements (
nums1[i] == nums2[j]
): This is our answer! Since both arrays are sorted and we're traversing from the beginning, this is guaranteed to be the minimum common element. Returnnums1[i]
immediately. -
First element smaller (
nums1[i] < nums2[j]
): The element atnums1[i]
cannot exist innums2
from positionj
onward (due to sorted order). Move pointeri
forward by incrementingi += 1
. -
Second element smaller (
nums1[i] > nums2[j]
): The element atnums2[j]
cannot exist innums1
from positioni
onward. Move pointerj
forward by incrementingj += 1
.
-
-
No Common Element Found: If the loop completes without finding any equal elements (meaning at least one pointer has reached the end of its array), return
-1
.
Why This Works:
- The sorted nature of both arrays ensures that when we find the first match, it's automatically the minimum.
- By always advancing the pointer pointing to the smaller element, we never miss a potential match.
- Each element in both arrays is visited at most once, giving us optimal time complexity of
O(m + n)
.
Space Complexity: O(1)
- only using two pointer variables and no additional data structures.
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 to see how the two-pointer technique works.
Example: nums1 = [1, 2, 4, 6, 8]
and nums2 = [2, 3, 4, 7]
We'll trace through each step showing the pointer positions and comparisons:
Initial Setup:
i = 0
,j = 0
nums1[i] = 1
,nums2[j] = 2
Step 1: Compare nums1[0] = 1
with nums2[0] = 2
- Since
1 < 2
, the element 1 cannot exist innums2
from position 0 onward (sincenums2
is sorted) - Action: Increment
i
to 1 - State:
i = 1
,j = 0
Step 2: Compare nums1[1] = 2
with nums2[0] = 2
- Since
2 == 2
, we found a common element! - Since we're traversing from the beginning of both sorted arrays, this is guaranteed to be the minimum common element
- Return:
2
Let's verify this is correct by identifying all common elements:
- Common elements: 2 (at
nums1[1]
andnums2[0]
), 4 (atnums1[2]
andnums2[2]
) - The minimum of these is 2 ✓
Alternative Scenario - No Common Element: Let's also see what happens when there's no common element.
Example: nums1 = [1, 3, 5]
and nums2 = [2, 4, 6]
Step 1: nums1[0] = 1
vs nums2[0] = 2
→ 1 < 2
→ increment i
to 1
Step 2: nums1[1] = 3
vs nums2[0] = 2
→ 3 > 2
→ increment j
to 1
Step 3: nums1[1] = 3
vs nums2[1] = 4
→ 3 < 4
→ increment i
to 2
Step 4: nums1[2] = 5
vs nums2[1] = 4
→ 5 > 4
→ increment j
to 2
Step 5: nums1[2] = 5
vs nums2[2] = 6
→ 5 < 6
→ increment i
to 3
Step 6: i = 3
equals length of nums1
, so exit loop
Since we exhausted nums1
without finding any common element, return -1
.
Solution Implementation
1class Solution:
2 def getCommon(self, nums1: List[int], nums2: List[int]) -> int:
3 """
4 Find the minimum common element between two sorted arrays.
5 Uses two-pointer technique to traverse both arrays simultaneously.
6
7 Args:
8 nums1: First sorted array in non-decreasing order
9 nums2: Second sorted array in non-decreasing order
10
11 Returns:
12 The minimum common element if exists, otherwise -1
13 """
14 # Initialize pointers for both arrays
15 pointer1 = 0
16 pointer2 = 0
17
18 # Get the lengths of both arrays
19 length1 = len(nums1)
20 length2 = len(nums2)
21
22 # Traverse both arrays using two pointers
23 while pointer1 < length1 and pointer2 < length2:
24 # If elements match, return the common element (minimum due to sorted order)
25 if nums1[pointer1] == nums2[pointer2]:
26 return nums1[pointer1]
27
28 # Move the pointer pointing to the smaller element
29 if nums1[pointer1] < nums2[pointer2]:
30 pointer1 += 1
31 else:
32 pointer2 += 1
33
34 # No common element found
35 return -1
36
1class Solution {
2 /**
3 * Finds the minimum common integer in two sorted arrays.
4 * Uses two-pointer technique to efficiently traverse both arrays.
5 *
6 * @param nums1 First sorted array in non-decreasing order
7 * @param nums2 Second sorted array in non-decreasing order
8 * @return The minimum common integer if exists, otherwise -1
9 */
10 public int getCommon(int[] nums1, int[] nums2) {
11 // Get the lengths of both arrays
12 int length1 = nums1.length;
13 int length2 = nums2.length;
14
15 // Initialize two pointers for traversing both arrays
16 int pointer1 = 0;
17 int pointer2 = 0;
18
19 // Traverse both arrays simultaneously until one is exhausted
20 while (pointer1 < length1 && pointer2 < length2) {
21 // If elements are equal, we found the minimum common element
22 if (nums1[pointer1] == nums2[pointer2]) {
23 return nums1[pointer1];
24 }
25
26 // Move the pointer pointing to the smaller element
27 if (nums1[pointer1] < nums2[pointer2]) {
28 pointer1++;
29 } else {
30 pointer2++;
31 }
32 }
33
34 // No common element found
35 return -1;
36 }
37}
38
1class Solution {
2public:
3 /**
4 * Find the minimum common integer in two sorted arrays.
5 * Uses two-pointer technique to efficiently find the first common element.
6 *
7 * @param nums1 First sorted array in non-decreasing order
8 * @param nums2 Second sorted array in non-decreasing order
9 * @return The minimum common integer if exists, otherwise -1
10 */
11 int getCommon(vector<int>& nums1, vector<int>& nums2) {
12 // Get the sizes of both arrays
13 int size1 = nums1.size();
14 int size2 = nums2.size();
15
16 // Initialize two pointers for traversing both arrays
17 int pointer1 = 0;
18 int pointer2 = 0;
19
20 // Traverse both arrays simultaneously
21 while (pointer1 < size1 && pointer2 < size2) {
22 // Found a common element - return immediately (minimum due to sorted order)
23 if (nums1[pointer1] == nums2[pointer2]) {
24 return nums1[pointer1];
25 }
26
27 // Move the pointer pointing to the smaller element
28 if (nums1[pointer1] < nums2[pointer2]) {
29 pointer1++;
30 } else {
31 pointer2++;
32 }
33 }
34
35 // No common element found
36 return -1;
37 }
38};
39
1/**
2 * Finds the smallest common element between two sorted arrays
3 * @param nums1 - First sorted array in non-decreasing order
4 * @param nums2 - Second sorted array in non-decreasing order
5 * @returns The minimum common element if exists, otherwise -1
6 */
7function getCommon(nums1: number[], nums2: number[]): number {
8 // Get the lengths of both arrays
9 const firstArrayLength: number = nums1.length;
10 const secondArrayLength: number = nums2.length;
11
12 // Initialize two pointers for traversing both arrays
13 let firstArrayIndex: number = 0;
14 let secondArrayIndex: number = 0;
15
16 // Use two-pointer technique to find common element
17 while (firstArrayIndex < firstArrayLength && secondArrayIndex < secondArrayLength) {
18 // Found a common element - return it immediately (will be the smallest due to sorted arrays)
19 if (nums1[firstArrayIndex] === nums2[secondArrayIndex]) {
20 return nums1[firstArrayIndex];
21 }
22
23 // Move the pointer pointing to the smaller element
24 if (nums1[firstArrayIndex] < nums2[secondArrayIndex]) {
25 // Current element in first array is smaller, move to next element
26 firstArrayIndex++;
27 } else {
28 // Current element in second array is smaller, move to next element
29 secondArrayIndex++;
30 }
31 }
32
33 // No common element found
34 return -1;
35}
36
Time and Space Complexity
The time complexity is O(m + n)
, where m
and n
are the lengths of nums1
and nums2
respectively. In the worst case, when there is no common element or the common element is at the end of one of the arrays, the algorithm needs to traverse through all elements of both arrays. Each iteration of the while loop either increments i
or j
, and the loop continues until one of the pointers reaches the end of its respective array. Therefore, the maximum number of iterations is m + n
.
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space. The variables i
, j
, m
, and n
are the only additional space used, regardless of the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Attempting to Use Set Intersection Without Considering Minimum
A common mistake is converting both arrays to sets and using set intersection, then finding the minimum:
Incorrect Approach:
def getCommon(self, nums1: List[int], nums2: List[int]) -> int:
common = set(nums1) & set(nums2)
return min(common) if common else -1
Why it's problematic:
- While this works correctly, it has O(m + n) space complexity instead of O(1)
- It doesn't leverage the fact that arrays are already sorted
- Finding min() requires additional O(k) time where k is the number of common elements
Better Solution: Stick with the two-pointer approach which finds the minimum directly in O(m + n) time with O(1) space.
2. Forgetting to Handle Duplicate Elements
Some might worry about duplicates and try to skip them unnecessarily:
Overcomplicated Approach:
def getCommon(self, nums1: List[int], nums2: List[int]) -> int:
i, j = 0, 0
while i < len(nums1) and j < len(nums2):
# Skip duplicates in nums1
while i + 1 < len(nums1) and nums1[i] == nums1[i + 1]:
i += 1
# Skip duplicates in nums2
while j + 1 < len(nums2) and nums2[j] == nums2[j + 1]:
j += 1
if nums1[i] == nums2[j]:
return nums1[i]
elif nums1[i] < nums2[j]:
i += 1
else:
j += 1
return -1
Why it's problematic:
- Adds unnecessary complexity
- The original solution handles duplicates naturally - when a match is found, it returns immediately
- Skipping duplicates doesn't improve the worst-case complexity
Better Solution: The original two-pointer approach handles duplicates correctly without special cases.
3. Using Binary Search Instead of Two Pointers
Some might think to iterate through one array and binary search in the other:
Suboptimal Approach:
def getCommon(self, nums1: List[int], nums2: List[int]) -> int:
for num in nums1:
left, right = 0, len(nums2) - 1
while left <= right:
mid = (left + right) // 2
if nums2[mid] == num:
return num
elif nums2[mid] < num:
left = mid + 1
else:
right = mid - 1
return -1
Why it's problematic:
- Time complexity becomes O(m * log n) instead of O(m + n)
- More complex to implement
- Less efficient for this specific problem
Better Solution: The two-pointer approach with O(m + n) time is more efficient than binary search's O(m * log n).
4. Not Returning Immediately Upon Finding First Match
Collecting all common elements before returning the minimum:
Inefficient Approach:
def getCommon(self, nums1: List[int], nums2: List[int]) -> int:
i, j = 0, 0
common_elements = []
while i < len(nums1) and j < len(nums2):
if nums1[i] == nums2[j]:
common_elements.append(nums1[i])
i += 1
j += 1
elif nums1[i] < nums2[j]:
i += 1
else:
j += 1
return common_elements[0] if common_elements else -1
Why it's problematic:
- Uses extra space O(k) where k is the number of common elements
- Continues traversing even after finding the minimum
- Inefficient when the minimum appears early
Better Solution: Return immediately when the first (minimum) common element is found, as in the original solution.
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
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
Want a Structured Path to Master System Design Too? Don’t Miss This!