3706. Maximum Distance Between Unequal Words in Array II š
Problem Description
You are given a string array words.
Your task is to find the maximum distance between two distinct indices i and j that satisfy the following conditions:
words[i] != words[j]ā the words at the two indices must be different, and- the distance between them is defined as
j - i + 1.
Return the maximum distance among all such valid pairs. If no valid pair exists (for example, when all words in the array are identical), return 0.
Key points to understand:
- The distance is not simply
j - i; it isj - i + 1, which counts the number of elements in the range from indexito indexj(inclusive). - The two indices must hold different words. Pairs where
words[i] == words[j]do not count. - To maximize
j - i + 1, we wantito be as small as possible andjto be as large as possible, while still keepingwords[i]andwords[j]different.
Example:
- If
words = ["a", "b", "c", "a"], the pair(i = 0, j = 2)giveswords[0] = "a"andwords[2] = "c", which are different, so the distance is2 - 0 + 1 = 3. The pair(i = 1, j = 3)also gives a distance of3. The pair(i = 0, j = 3)is invalid because both words are"a". Hence the answer is3. - If
words = ["x", "x", "x"], every pair has equal words, so no valid pair exists, and the answer is0.
How We Pick the Algorithm
Why Two pointers?
This problem maps to Two pointers through a short path in the full flowchart.
The optimal pair must anchor at either index 0 or n-1, reducing the search to comparing each word against both endpoints in one pass.
Open in FlowchartIntuition
A brute-force approach would check every pair (i, j) and take the maximum distance among pairs with different words, costing O(n^2) time. But a key observation lets us do much better.
To maximize j - i + 1, we want i to be small and j to be large. The most extreme candidates are the two ends of the array: index 0 and index n - 1.
Claim: in any optimal pair, at least one of the two indices must be an endpoint of the array (0 or n - 1).
Why? Suppose the best pair (i, j) has neither index at an endpoint, i.e., 0 < i and j < n - 1. Then:
words[0]must equalwords[j]ā otherwise the pair(0, j)would be valid and longer, contradicting optimality.words[n - 1]must equalwords[i]ā otherwise the pair(i, n - 1)would be valid and longer.
But since words[i] != words[j], combining the two equalities gives words[n - 1] != words[0]. That makes (0, n - 1) itself a valid pair with distance n, the largest possible ā again contradicting the assumption that (i, j) was optimal.
So the assumption fails, and every optimal answer involves words[0] or words[n - 1].
This immediately suggests a single-pass strategy: for each index i, only two pairings matter ā
- pair
iwith the first word: ifwords[i] != words[0], the distance isi - 0 + 1 = i + 1; - pair
iwith the last word: ifwords[i] != words[n - 1], the distance is(n - 1) - i + 1 = n - i.
Taking the maximum over all such candidates covers every possible optimal pair, reducing the problem to a simple O(n) scan with O(1) extra space.
Solution Approach
Based on the observation that at least one index of the optimal pair must be an endpoint, the implementation becomes a single pass over the array, comparing every word against the first word and the last word.
Step-by-Step Walkthrough
Step 1: Initialization
n = len(words)
ans = 0
nis the length of the array.ansholds the best distance found so far. Starting it at0automatically handles the "no valid pair exists" case ā if every comparison fails,ansis never updated and0is returned.
Step 2: Single pass ā compare each word with both endpoints
for i in range(n):
if words[i] != words[0]:
ans = max(ans, i + 1)
if words[i] != words[-1]:
ans = max(ans, n - i)
For each index i, two candidate pairs are evaluated:
- Pair
(0, i)ā ifwords[i] != words[0], this is a valid pair, and its distance isi - 0 + 1 = i + 1. - Pair
(i, n - 1)ā ifwords[i] != words[-1](i.e.,words[n - 1]), this is a valid pair, and its distance is(n - 1) - i + 1 = n - i.
Each valid candidate is folded into ans via max.
Two boundary details worth noting:
- When
i = 0, the first conditionwords[0] != words[0]is always false, so the invalid "pair" of an index with itself is never counted. The same holds fori = n - 1in the second condition. - If
words[0] != words[n - 1], the loop naturally captures the maximum possible answernā for example, ati = n - 1the first check yields(n - 1) + 1 = n.
Step 3: Return the result
return ans
Why This Covers All Cases
The proof from the intuition guarantees that any optimal pair (i, j) has i = 0 or j = n - 1:
- If
i = 0, the pair is found by the firstifwhen the loop reaches indexj. - If
j = n - 1, the pair is found by the secondifwhen the loop reaches indexi.
So no optimal answer can be missed by this scan.
Data Structures and Patterns
- No auxiliary data structures are needed ā just two scalar variables.
- The pattern is a greedy / endpoint-anchoring technique: instead of enumerating all
O(n^2)pairs, a structural property of the optimum shrinks the candidate set toO(n)pairs anchored at the array's two ends.
Complexity Analysis
- Time complexity:
O(n)ā a single traversal of the array, with each iteration doing constant work (two string comparisons; if string lengths are bounded by a constant, each comparison isO(1)). - Space complexity:
O(1)ā onlynandansare stored, independent of input size.
Alternative Perspective: Two-Pointer Variant
The same endpoint insight admits another O(n) formulation. Find the largest j with words[j] != words[0] and the smallest i with words[i] != words[n - 1]; the answer is max(j + 1, n - i) (or 0 if neither exists). This computes identical results, since both methods exhaust exactly the pairs anchored at an endpoint ā the single-pass version above simply merges both searches into one loop.
Example Walkthrough
Let's trace the single-pass solution on words = ["a", "b", "c", "a"].
Setup:
n = 4- First word:
words[0] = "a" - Last word:
words[-1] = "a"(i.e.,words[3]) ans = 0
Loop execution:
i | words[i] | Check 1: words[i] != words[0]? | Candidate i + 1 | Check 2: words[i] != words[-1]? | Candidate n - i | ans after |
|---|---|---|---|---|---|---|
| 0 | "a" | "a" != "a" ā No | ā | "a" != "a" ā No | ā | 0 |
| 1 | "b" | "b" != "a" ā Yes | 1 + 1 = 2 | "b" != "a" ā Yes | 4 - 1 = 3 | 3 |
| 2 | "c" | "c" != "a" ā Yes | 2 + 1 = 3 | "c" != "a" ā Yes | 4 - 2 = 2 | 3 |
| 3 | "a" | "a" != "a" ā No | ā | "a" != "a" ā No | ā | 3 |
Detailed reasoning per step:
i = 0: Both checks compare"a"against"a", so neither passes. This is exactly how the algorithm avoids pairing an index with itself ā no update occurs.i = 1:words[1] = "b"differs from the first word, giving valid pair(0, 1)with distance2. It also differs from the last word, giving valid pair(1, 3)with distance4 - 1 = 3. Nowans = 3.i = 2:words[2] = "c"differs from the first word, giving pair(0, 2)with distance3ā ties the current best. It also differs from the last word, giving pair(2, 3)with distance2ā no improvement.ansstays3.i = 3:words[3] = "a"matches both endpoints, so the invalid pair(0, 3)(both"a") is correctly skipped.
Result: ans = 3 ā
This matches the expected answer: the optimal pairs are (0, 2) ā ["a", ..., "c"] and (1, 3) ā ["b", ..., "a"], both with distance 3. Notice how every candidate the loop evaluated was anchored at index 0 or index n - 1, confirming the endpoint observation ā the invalid full-range pair (0, 3) was the only endpoint pair rejected.
Edge case check ā words = ["x", "x", "x"]:
Every comparison words[i] != "x" fails at all three indices, so ans is never updated and the function returns 0, correctly reporting that no valid pair exists.
Solution Implementation
1class Solution:
2 def maxDistance(self, words: List[str]) -> int:
3 # Total number of words in the array
4 num_words = len(words)
5 # Maximum distance found so far
6 max_dist = 0
7
8 for i in range(num_words):
9 # If the current word differs from the first word,
10 # the distance between index 0 and index i is (i - 0 + 1) = i + 1
11 if words[i] != words[0]:
12 max_dist = max(max_dist, i + 1)
13 # If the current word differs from the last word,
14 # the distance between index i and the last index is (num_words - 1 - i + 1) = num_words - i
15 if words[i] != words[-1]:
16 max_dist = max(max_dist, num_words - i)
17
18 return max_dist
191class Solution {
2 public int maxDistance(String[] words) {
3 // Total number of words in the array
4 int wordCount = words.length;
5
6 // Tracks the maximum distance found so far
7 int maxDistance = 0;
8
9 // Iterate through every word once
10 for (int index = 0; index < wordCount; ++index) {
11 // If the current word differs from the FIRST word,
12 // the span from index 0 to the current index is a valid candidate.
13 // Its length is (index - 0 + 1) = index + 1.
14 if (!words[index].equals(words[0])) {
15 maxDistance = Math.max(maxDistance, index + 1);
16 }
17
18 // If the current word differs from the LAST word,
19 // the span from the current index to index (wordCount - 1) is a valid candidate.
20 // Its length is (wordCount - 1 - index + 1) = wordCount - index.
21 if (!words[index].equals(words[wordCount - 1])) {
22 maxDistance = Math.max(maxDistance, wordCount - index);
23 }
24 }
25
26 // Returns 0 if all words are identical (no valid pair exists)
27 return maxDistance;
28 }
29}
301class Solution {
2public:
3 int maxDistance(vector<string>& words) {
4 int wordCount = words.size();
5 int maxDist = 0;
6
7 // Iterate over every word, treating it as a potential endpoint
8 // of a pair of unequal words.
9 for (int i = 0; i < wordCount; ++i) {
10 // If the current word differs from the first word,
11 // the pair (0, i) is valid; its distance is i - 0 + 1.
12 if (words[i] != words[0]) {
13 maxDist = max(maxDist, i + 1);
14 }
15
16 // If the current word differs from the last word,
17 // the pair (i, wordCount - 1) is valid; its distance is
18 // (wordCount - 1) - i + 1 = wordCount - i.
19 if (words[i] != words[wordCount - 1]) {
20 maxDist = max(maxDist, wordCount - i);
21 }
22 }
23
24 // If all words are identical, maxDist remains 0.
25 return maxDist;
26 }
27};
281/**
2 * Finds the maximum distance between two indices i and j
3 * such that words[i] !== words[j].
4 *
5 * Key insight: the optimal pair must involve either the first
6 * or the last element of the array. If words[i] differs from
7 * words[0], the distance is i + 1 (1-based span); if words[i]
8 * differs from words[n - 1], the distance is n - i.
9 *
10 * @param words - the input array of strings
11 * @returns the maximum distance between two unequal words,
12 * or 0 if all words are identical
13 */
14function maxDistance(words: string[]): number {
15 // Total number of words in the array
16 const n: number = words.length;
17 // Holds the maximum distance found so far
18 let ans: number = 0;
19
20 // Iterate over every word and compare it against
21 // the first and the last word of the array
22 for (let i = 0; i < n; i++) {
23 // If the current word differs from the first word,
24 // the candidate distance is i + 1
25 if (words[i] !== words[0]) {
26 ans = Math.max(ans, i + 1);
27 }
28 // If the current word differs from the last word,
29 // the candidate distance is n - i
30 if (words[i] !== words[n - 1]) {
31 ans = Math.max(ans, n - i);
32 }
33 }
34
35 // Return the maximum distance (0 if no unequal pair exists)
36 return ans;
37}
38Time and Space Complexity
-
Time Complexity:
O(n), wherenis the length of the arraywords. The code iterates through the array exactly once with a single loop. In each iteration, it performs a constant number of operations: two string comparisons (words[i] != words[0]andwords[i] != words[-1]) and twomaxupdates. Therefore, the total work scales linearly with the size of the input. -
Space Complexity:
O(1). The algorithm only uses a fixed number of extra variables (n,ans, and the loop indexi), regardless of the input size. No additional data structures are allocated, so the auxiliary space remains constant.
Pattern Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Computing the distance as j - i instead of j - i + 1
This is the single most frequent mistake. The problem defines distance as the count of elements in the inclusive range [i, j], not the index difference.
Incorrect:
for i in range(num_words):
if words[i] != words[0]:
max_dist = max(max_dist, i) # off by one
if words[i] != words[-1]:
max_dist = max(max_dist, num_words - 1 - i) # off by one
For words = ["a", "b", "c", "a"], this returns 2 instead of the correct 3. The bug is easy to miss because the code still "looks symmetric" and passes trivial cases like all-identical arrays (which return 0 either way).
Fix: Always translate the pair (i, j) into j - i + 1:
- Pair
(0, i)ā distancei + 1 - Pair
(i, n - 1)ā distancen - i
A quick sanity check: when words[0] != words[n - 1], the answer must be exactly n (the whole array). If your formula yields n - 1 for that case, you have an off-by-one error.
Pitfall 2: Assuming the optimal pair must be (0, n - 1) and only checking the two endpoints against each other
A tempting "shortcut" is:
return num_words if words[0] != words[-1] else 0 # WRONG
This fails whenever the first and last words are equal but a valid pair still exists, e.g. words = ["a", "b", "a"]. Here words[0] == words[2], yet (0, 1) and (1, 2) are both valid with distance 2. The correct structural claim is weaker: at least one index of an optimal pair is an endpoint ā not both. You still must scan all indices and anchor each against the first word and the last word separately.
Pitfall 3: Comparing only against words[0] (or only against words[-1])
Checking just one anchor breaks symmetry:
for i in range(num_words):
if words[i] != words[0]:
max_dist = max(max_dist, i + 1) # missing the second check
For words = ["b", "a", "a", "a"], the largest index differing from words[0] is i = 3, giving the correct 4. But for words = ["a", "a", "a", "b"] mirrored cases such as ["a", "b", "b", "b"] still work ā the real failure shows up in inputs like ["a", "b", "a", "a"]: the only index differing from words[0] is i = 1, yielding 2, while the true answer is 3 from pair (1, 3) anchored at the last element. Both endpoint checks are required to cover both halves of the proof.
Pitfall 4: Brute-forcing all pairs and hitting O(n²) time limits
for i in range(num_words):
for j in range(i + 1, num_words):
if words[i] != words[j]:
max_dist = max(max_dist, j - i + 1)
This is correct but quadratic, and on large inputs (e.g., n up to 10^5) it times out. The endpoint-anchoring insight reduces the candidate set to O(n) pairs. If you do start with brute force, an easy partial optimization ā breaking the inner loop from the right side at the first mismatch ā already hints at the linear solution.
Pitfall 5: Forgetting the "all identical" / single-element edge cases
If every word is the same (including n = 1), no valid pair exists and the answer must be 0. Solutions that initialize the answer to 1, or that unconditionally return num_words after some check, fail here. Initializing max_dist = 0 and only updating it on a confirmed mismatch handles this for free ā verify with words = ["x", "x", "x"] (expect 0) and words = ["x"] (expect 0).
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapA heap is a ...?
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!