3682. Minimum Index Sum of Common Elements 🔒
Problem Description
You are given two integer arrays nums1 and nums2, both of the same length n.
A pair of indices (i, j) is called a good pair if the value at index i in the first array equals the value at index j in the second array, i.e., nums1[i] == nums2[j].
Your task is to find the smallest possible index sum i + j among all good pairs.
- If at least one good pair exists, return the minimum value of
i + j. - If the two arrays share no common values at all (meaning no good pair can be formed), return
-1.
Example:
Suppose nums1 = [1, 2, 3] and nums2 = [2, 4, 1].
- The value
1appears at index0innums1and index2innums2, giving a good pair(0, 2)with sum0 + 2 = 2. - The value
2appears at index1innums1and index0innums2, giving a good pair(1, 0)with sum1 + 0 = 1.
The minimum index sum among all good pairs is 1, so the answer is 1.
The key challenge is to do this efficiently: rather than checking every possible (i, j) combination (which would take O(n^2) time), you can record the earliest occurrence of each value in nums2 using a hash map, then scan nums1 once to compute the best answer in O(n) time.
How We Pick the Algorithm
Why Hash Table / Counting?
This problem maps to Hash Table / Counting through a short path in the full flowchart.
The problem finds the minimum index sum of common elements between two arrays by recording the first occurrence of each value in one array and scanning the other.
Open in FlowchartIntuition
The brute-force approach would be to check every pair (i, j), compare nums1[i] with nums2[j], and track the smallest i + j. That works, but it costs O(n^2) time. The natural question is: where is the wasted work?
The key observation is this: for any value x that appears in both arrays, the only occurrence of x in nums2 that ever matters is its first (smallest-index) occurrence. If x appears at indices j1 < j2 in nums2, then for any i in nums1, the pair (i, j1) always gives a smaller sum than (i, j2). So all later occurrences of x in nums2 can be safely ignored.
This insight immediately suggests a preprocessing step: walk through nums2 once and record, in a hash map d, the earliest index of each distinct value. Since we iterate from left to right, we simply skip a value if it's already in the map — the first index we stored is guaranteed to be the smallest.
Once that map exists, the problem collapses into a single pass over nums1. For each element nums1[i], a lookup tells us in O(1) whether the value exists in nums2, and if so, the best possible partner index d[nums1[i]]. The candidate sum is i + d[nums1[i]], and we keep the minimum across all i.
By symmetry, the same argument applies to nums1: only the first occurrence of each value in nums1 could ever produce the minimum, but since we take min over all candidates anyway, scanning every element of nums1 handles this automatically without extra logic.
Finally, initializing the answer to inf gives a clean way to detect the "no good pair" case — if it never gets updated, no common value exists, and we return -1. The result is an O(n) time, O(n) space solution that trades a hash map for the quadratic comparison loop.
Solution Approach
The solution uses a hash map to eliminate the nested loop and achieve linear time. The implementation breaks down into three clear steps.
Step 1: Build the hash map from nums2.
d = {}
for i, x in enumerate(nums2):
if x not in d:
d[x] = i
We iterate through nums2 and store each value x as a key, mapped to its index i. The guard if x not in d ensures that only the first occurrence of each value is recorded. Because the traversal goes left to right, the stored index is automatically the smallest one for that value — which is the only index that could ever contribute to a minimum sum.
Step 2: Scan nums1 and compute candidate sums.
ans = inf
for i, x in enumerate(nums1):
if x in d:
ans = min(ans, i + d[x])
We initialize ans to infinity as a sentinel meaning "no good pair found yet." Then, for each element x = nums1[i]:
- We check in
O(1)whetherxexists in the mapd. - If it does,
(i, d[x])is a good pair, andd[x]is the best possible partner index innums2for this value. The candidate index sum isi + d[x]. - We update
answithmin(ans, i + d[x]), so after the loop finishes,ansholds the smallest sum across all good pairs.
Note that we don't need to deduplicate values in nums1: if a value repeats, its later occurrences produce strictly larger sums, and the min operation discards them naturally.
Step 3: Handle the no-pair case.
return -1 if ans == inf else ans
If ans was never updated, the two arrays share no common element, so we return -1. Otherwise, we return the computed minimum.
Complexity Analysis
- Time complexity:
O(n)— one pass overnums2to build the map and one pass overnums1to query it, with each hash map operation takingO(1)on average. - Space complexity:
O(n)— in the worst case, every element ofnums2is distinct and the map storesnentries.
Alternative perspective: the roles of the two arrays are symmetric. One could equally build the map from nums1 and iterate over nums2; correctness and complexity are identical. A brute-force double loop comparing all (i, j) pairs would also work but would run in O(n^2), which the hash map approach improves upon decisively.
Example Walkthrough
Let's trace the algorithm with nums1 = [5, 3, 7, 3] and nums2 = [3, 9, 5, 3].
Step 1: Build the hash map from nums2.
We walk through nums2 left to right, recording only the first occurrence of each value:
Index i | Value x | Action | Map d |
|---|---|---|---|
| 0 | 3 | New value → store | {3: 0} |
| 1 | 9 | New value → store | {3: 0, 9: 1} |
| 2 | 5 | New value → store | {3: 0, 9: 1, 5: 2} |
| 3 | 3 | Already in map → skip | {3: 0, 9: 1, 5: 2} |
Note how the duplicate 3 at index 3 is ignored — pairing with index 0 always gives a smaller sum, so index 3 can never produce the answer.
Step 2: Scan nums1 and compute candidate sums.
We initialize ans = inf and check each element of nums1 against the map:
Index i | Value x | In d? | Candidate i + d[x] | ans |
|---|---|---|---|---|
| 0 | 5 | Yes, d[5] = 2 | 0 + 2 = 2 | 2 |
| 1 | 3 | Yes, d[3] = 0 | 1 + 0 = 1 | 1 |
| 2 | 7 | No | — | 1 |
| 3 | 3 | Yes, d[3] = 0 | 3 + 0 = 3 | 1 |
Two things worth observing:
- The value
7has no match innums2, so it contributes nothing — theO(1)lookup quietly skips it. - The repeated
3innums1at index3produces a worse candidate (3) than its earlier occurrence (1), andmindiscards it automatically. No deduplication ofnums1was needed.
Step 3: Return the result.
Since ans = 1 was updated from inf, at least one good pair exists, and we return 1 — achieved by the pair (i, j) = (1, 0), where nums1[1] == nums2[0] == 3.
For contrast, if the inputs were nums1 = [1, 2] and nums2 = [7, 8], no lookup would ever succeed, ans would remain inf, and the function would return -1.
The entire process used one pass over each array — O(n) time — instead of checking all 4 × 4 = 16 index pairs as brute force would.
Solution Implementation
1class Solution:
2 def minimumSum(self, nums1: List[int], nums2: List[int]) -> int:
3 # Map each value in nums2 to the index of its first occurrence.
4 # Only the first (smallest) index matters for minimizing the sum.
5 first_index = {}
6 for index, value in enumerate(nums2):
7 if value not in first_index:
8 first_index[value] = index
9
10 # Initialize the answer with infinity as a sentinel value.
11 min_sum = inf
12
13 # Iterate over nums1; for every value that also exists in nums2,
14 # compute the sum of the two indices and keep the minimum.
15 for index, value in enumerate(nums1):
16 if value in first_index:
17 min_sum = min(min_sum, index + first_index[value])
18
19 # If no common value was found, return -1; otherwise return the minimum sum.
20 return -1 if min_sum == inf else min_sum
211class Solution {
2 /**
3 * Finds the minimum sum of indices (i + j) such that nums1[i] == nums2[j].
4 * Returns -1 if no such pair of indices exists.
5 *
6 * @param nums1 the first integer array
7 * @param nums2 the second integer array
8 * @return the minimum index sum, or -1 if no common value is found
9 */
10 public int minimumSum(int[] nums1, int[] nums2) {
11 int n = nums1.length;
12
13 // A large constant representing "infinity" (no valid answer found yet)
14 final int INF = 1 << 30;
15
16 // Map each value in nums2 to the smallest index at which it appears.
17 // putIfAbsent ensures only the first (smallest) index is stored.
18 Map<Integer, Integer> valueToMinIndex = new HashMap<>();
19 for (int j = 0; j < n; j++) {
20 valueToMinIndex.putIfAbsent(nums2[j], j);
21 }
22
23 int minIndexSum = INF;
24
25 // For each value in nums1, check if it also exists in nums2.
26 // If so, compute the sum of the current index and the smallest
27 // matching index in nums2, and keep track of the minimum.
28 for (int i = 0; i < n; i++) {
29 Integer j = valueToMinIndex.get(nums1[i]);
30 if (j != null) {
31 minIndexSum = Math.min(minIndexSum, i + j);
32 }
33 }
34
35 // If no common value was found, return -1; otherwise return the result.
36 return minIndexSum == INF ? -1 : minIndexSum;
37 }
38}
391class Solution {
2public:
3 int minimumSum(vector<int>& nums1, vector<int>& nums2) {
4 int n = nums1.size();
5 const int INF = INT_MAX;
6
7 // Map each value in nums2 to its earliest (smallest) index.
8 unordered_map<int, int> firstIndex;
9 for (int i = 0; i < n; ++i) {
10 // Only record the first occurrence to keep the index minimal.
11 if (!firstIndex.count(nums2[i])) {
12 firstIndex[nums2[i]] = i;
13 }
14 }
15
16 int ans = INF;
17
18 // For each value in nums1, check if the same value exists in nums2.
19 // If so, the cost is the sum of the current index and the earliest
20 // index of that value in nums2; keep the minimum over all matches.
21 for (int i = 0; i < n; ++i) {
22 auto it = firstIndex.find(nums1[i]);
23 if (it != firstIndex.end()) {
24 ans = min(ans, i + it->second);
25 }
26 }
27
28 // If no common value was found, return -1.
29 return ans == INF ? -1 : ans;
30 }
31};
321/**
2 * Finds the minimum sum of indices (i + j) such that nums1[i] === nums2[j].
3 * Returns -1 if no such pair of indices exists.
4 *
5 * @param nums1 - The first array of numbers
6 * @param nums2 - The second array of numbers
7 * @returns The minimum index sum, or -1 if no matching value exists in both arrays
8 */
9function minimumSum(nums1: number[], nums2: number[]): number {
10 // Length of the input arrays
11 const length: number = nums1.length;
12
13 // A large value representing "infinity" (used as the initial answer)
14 const INF: number = 1 << 30;
15
16 // Map each value in nums2 to the smallest index at which it appears
17 const valueToMinIndex: Map<number, number> = new Map<number, number>();
18 for (let j = 0; j < length; j++) {
19 // Only record the first (smallest) index for each value
20 if (!valueToMinIndex.has(nums2[j])) {
21 valueToMinIndex.set(nums2[j], j);
22 }
23 }
24
25 // Initialize the answer with "infinity"
26 let answer: number = INF;
27
28 // Iterate over nums1 and look for matching values in nums2
29 for (let i = 0; i < length; i++) {
30 const value: number = nums1[i];
31 if (valueToMinIndex.has(value)) {
32 // Update the answer with the smaller index sum
33 answer = Math.min(answer, i + (valueToMinIndex.get(value) as number));
34 }
35 }
36
37 // If no matching value was found, return -1; otherwise, return the answer
38 return answer === INF ? -1 : answer;
39}
40Time and Space Complexity
-
Time Complexity:
O(n + m), wherenis the length ofnums1andmis the length ofnums2. The code iterates throughnums2once to build the dictionaryd(takingO(m)time), and then iterates throughnums1once to find the minimum index sum (takingO(n)time, since each dictionary lookup isO(1)on average). If both arrays have the same lengthn, this simplifies toO(n). -
Space Complexity:
O(m), wheremis the length ofnums2. The dictionarydstores at most one entry per distinct element innums2, requiringO(m)space in the worst case. If both arrays have the same lengthn, this simplifies toO(n).
Pattern Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Overwriting earlier indices when building the hash map
The most frequent mistake is building the map from nums2 without guarding against duplicates:
# WRONG: later occurrences overwrite earlier ones
d = {}
for i, x in enumerate(nums2):
d[x] = i
If a value appears multiple times in nums2, this stores its last index instead of its first. Since only the smallest index for each value can ever minimize i + j, the computed answer may be larger than the true minimum.
Example: nums1 = [5], nums2 = [5, 9, 5].
- Correct answer: pair
(0, 0)with sum0. - Buggy version stores
d[5] = 2and returns0 + 2 = 2.
Solution: Keep the guard so only the first occurrence is recorded:
for i, x in enumerate(nums2):
if x not in d:
d[x] = i
An equivalent fix is to iterate nums2 in reverse with unconditional assignment (d[x] = i), since the last write would then be the leftmost index — but the explicit guard is clearer about intent.
Pitfall 2: Using 0 or -1 as the "not found" sentinel
Initializing min_sum = 0 is broken because 0 is a valid answer (pair (0, 0)), and min(0, anything) never updates. Similarly, initializing to -1 makes the min comparison always pick -1.
Solution: Use float('inf') (or math.inf) as the sentinel, then translate it to -1 only at the very end:
return -1 if min_sum == inf else min_sum
Alternatively, use a separate boolean flag found to track whether any good pair exists.
Pitfall 3: Building the map and querying it with the same array
A subtle copy-paste error is enumerating the same array twice — e.g., building first_index from nums2 but then also looping over nums2 instead of nums1 in the second pass. The code still runs without error and may even pass trivial tests where the arrays overlap heavily, which makes the bug easy to miss.
Solution: Double-check that the two passes operate on different arrays, and verify with a test case where the arrays differ, such as nums1 = [3], nums2 = [7] (expected output -1).
Pitfall 4: Returning early instead of checking all candidates
Some implementations return i + d[x] the moment the first match in nums1 is found. A later element of nums1 with a much smaller partner index in nums2 can still yield a smaller sum.
Example: nums1 = [8, 2], nums2 = [2, 9, 9, 8].
- First match found: value
8ati = 0, partner index3, sum3. - True minimum: value
2ati = 1, partner index0, sum1.
Solution: Always finish the full scan of nums1, accumulating the minimum with min(min_sum, i + d[x]). (A valid optimization does exist — you may break out of the loop once i >= min_sum, because every future sum is at least i — but a plain early return on the first match is incorrect.)
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhat's the relationship between a tree and a graph?
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 If you prefer videos here's a video that explains recursion in a fun and easy way 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 him
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 describes how the time needed
Want a Structured Path to Master System Design Too? Don’t Miss This!