245. Shortest Word Distance III 🔒
Problem Description
You are given an array of strings wordsDict
and two target strings word1
and word2
that both exist in the array. Your task is to find the shortest distance between any occurrence of these two words in the list.
The distance between two words is calculated as the absolute difference between their indices in the array. For example, if word1
appears at index i
and word2
appears at index j
, the distance between them is |i - j|
.
An important note is that word1
and word2
might be the same string. When they are the same, you need to find the minimum distance between two different occurrences of that word in the array. The problem guarantees that when word1
equals word2
, there are at least two occurrences of that word in the array.
The solution handles two distinct cases:
- When
word1 == word2
: Track consecutive occurrences of the same word and calculate the minimum distance between them - When
word1 != word2
: Track the most recent positions of both words and update the minimum distance whenever both have been found
The algorithm maintains a running minimum distance, initially set to the length of the array (maximum possible distance). As it iterates through the array, it updates this minimum whenever it finds valid pairs of the target words.
Intuition
The key insight is that we need to track positions of words as we scan through the array, but the strategy differs based on whether we're looking for the same word or different words.
When looking for the minimum distance between two different words, we can use a greedy approach. As we scan the array, we only need to remember the most recent position of each word. Why? Because if we find word1
at position i
, the closest word2
to it would be the most recently seen word2
before position i
or the next word2
we encounter after position i
. There's no need to remember all previous positions.
The situation becomes slightly different when word1
and word2
are the same. In this case, we're looking for the minimum distance between two occurrences of the same word. We can't compare a word's position with itself, so we need to track consecutive occurrences. Each time we find the word, we calculate the distance from the previous occurrence and update our minimum if needed.
The initialization of indices to -1
serves as a flag to indicate whether we've encountered the words yet. For the different words case, we only start calculating distances after we've seen both words at least once (both indices are not -1
). For the same word case, we start calculating distances after seeing the word at least twice.
By maintaining a running minimum and updating it whenever we find valid pairs, we ensure we've considered all possible distances by the time we finish scanning the array. The initial value of ans = len(wordsDict)
acts as an upper bound since no distance in the array can exceed the array's length.
Solution Approach
The implementation uses case analysis to handle two distinct scenarios based on whether word1
and word2
are the same string.
Case 1: When word1 == word2
We need to find the minimum distance between two different occurrences of the same word. The algorithm:
- Initializes a variable
j = -1
to track the previous occurrence index - Iterates through
wordsDict
with indexi
- When we find the target word:
- If
j != -1
(meaning we've seen the word before), calculate the distancei - j
and update the minimum - Update
j = i
to remember this position for the next occurrence
- If
- This ensures we're always comparing consecutive occurrences of the same word
Case 2: When word1 != word2
We need to find the minimum distance between any occurrence of word1
and any occurrence of word2
. The algorithm:
- Initializes two variables
i = j = -1
to track the most recent positions ofword1
andword2
- Iterates through
wordsDict
with indexk
- When we find
word1
, updatei = k
- When we find
word2
, updatej = k
- If both
i != -1
andj != -1
(both words have been found at least once), calculate the distanceabs(i - j)
and update the minimum - This greedy approach works because at any point, the closest pair involves the most recent occurrence of one word with the most recent occurrence of the other
The time complexity is O(n)
where n
is the length of wordsDict
, as we make a single pass through the array. The space complexity is O(1)
as we only use a constant amount of extra variables regardless of input size.
The initial value ans = len(wordsDict)
serves as an upper bound that will definitely be replaced by a smaller valid distance during execution.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let me demonstrate the solution approach with two examples to cover both cases.
Example 1: Different words
wordsDict = ["the", "quick", "brown", "fox", "quick"] word1 = "quick", word2 = "fox"
Let's trace through the algorithm:
- Initialize:
ans = 5
(array length),i = -1
,j = -1
- Index 0: "the" → not a target word, continue
- Index 1: "quick" → matches
word1
, seti = 1
- Both words not found yet (
j = -1
), no distance calculation
- Both words not found yet (
- Index 2: "brown" → not a target word, continue
- Index 3: "fox" → matches
word2
, setj = 3
- Both words found (
i = 1
,j = 3
) - Calculate distance:
|1 - 3| = 2
- Update
ans = min(5, 2) = 2
- Both words found (
- Index 4: "quick" → matches
word1
, seti = 4
- Both words found (
i = 4
,j = 3
) - Calculate distance:
|4 - 3| = 1
- Update
ans = min(2, 1) = 1
- Both words found (
Result: 1 (minimum distance between "quick" at index 4 and "fox" at index 3)
Example 2: Same word
wordsDict = ["a", "c", "a", "b", "a"] word1 = "a", word2 = "a"
Since word1 == word2
, we use the same-word logic:
- Initialize:
ans = 5
(array length),j = -1
- Index 0: "a" → matches target word
j = -1
(first occurrence), no distance calculation- Update
j = 0
- Index 1: "c" → not the target word, continue
- Index 2: "a" → matches target word
j = 0
(previous occurrence exists)- Calculate distance:
2 - 0 = 2
- Update
ans = min(5, 2) = 2
- Update
j = 2
- Index 3: "b" → not the target word, continue
- Index 4: "a" → matches target word
j = 2
(previous occurrence exists)- Calculate distance:
4 - 2 = 2
- Update
ans = min(2, 2) = 2
- Update
j = 4
Result: 2 (minimum distance between consecutive occurrences of "a")
Solution Implementation
1class Solution:
2 def shortestWordDistance(self, wordsDict: List[str], word1: str, word2: str) -> int:
3 # Initialize minimum distance to maximum possible value (length of array)
4 min_distance = len(wordsDict)
5
6 # Case 1: When both words are the same
7 if word1 == word2:
8 # Track the previous occurrence of the word
9 prev_index = -1
10
11 # Iterate through the words dictionary
12 for current_index, word in enumerate(wordsDict):
13 if word == word1:
14 # If we've seen this word before, calculate distance
15 if prev_index != -1:
16 min_distance = min(min_distance, current_index - prev_index)
17 # Update previous index for next iteration
18 prev_index = current_index
19
20 # Case 2: When the words are different
21 else:
22 # Track the most recent positions of both words
23 word1_index = -1
24 word2_index = -1
25
26 # Iterate through the words dictionary
27 for current_index, word in enumerate(wordsDict):
28 # Update position if we find word1
29 if word == word1:
30 word1_index = current_index
31 # Update position if we find word2
32 if word == word2:
33 word2_index = current_index
34
35 # If both words have been found at least once, calculate distance
36 if word1_index != -1 and word2_index != -1:
37 min_distance = min(min_distance, abs(word1_index - word2_index))
38
39 return min_distance
40
1class Solution {
2 public int shortestWordDistance(String[] wordsDict, String word1, String word2) {
3 // Initialize minimum distance to maximum possible value (array length)
4 int minDistance = wordsDict.length;
5
6 // Case 1: When word1 and word2 are the same
7 if (word1.equals(word2)) {
8 // Track the previous occurrence of the word
9 int previousIndex = -1;
10
11 // Iterate through the array to find all occurrences
12 for (int currentIndex = 0; currentIndex < wordsDict.length; currentIndex++) {
13 if (wordsDict[currentIndex].equals(word1)) {
14 // If we've seen this word before, calculate distance
15 if (previousIndex != -1) {
16 minDistance = Math.min(minDistance, currentIndex - previousIndex);
17 }
18 // Update previous occurrence to current position
19 previousIndex = currentIndex;
20 }
21 }
22 } else {
23 // Case 2: When word1 and word2 are different
24 int word1Index = -1; // Track last occurrence of word1
25 int word2Index = -1; // Track last occurrence of word2
26
27 // Iterate through the array to find occurrences of both words
28 for (int currentIndex = 0; currentIndex < wordsDict.length; currentIndex++) {
29 // Update index when word1 is found
30 if (wordsDict[currentIndex].equals(word1)) {
31 word1Index = currentIndex;
32 }
33
34 // Update index when word2 is found
35 if (wordsDict[currentIndex].equals(word2)) {
36 word2Index = currentIndex;
37 }
38
39 // Calculate distance if both words have been found at least once
40 if (word1Index != -1 && word2Index != -1) {
41 minDistance = Math.min(minDistance, Math.abs(word1Index - word2Index));
42 }
43 }
44 }
45
46 return minDistance;
47 }
48}
49
1class Solution {
2public:
3 int shortestWordDistance(vector<string>& wordsDict, string word1, string word2) {
4 int n = wordsDict.size();
5 int minDistance = n; // Initialize with maximum possible distance
6
7 // Case 1: When word1 and word2 are the same
8 if (word1 == word2) {
9 int prevIndex = -1; // Store the previous occurrence of the word
10
11 for (int i = 0; i < n; ++i) {
12 if (wordsDict[i] == word1) {
13 // If we've seen this word before, calculate distance
14 if (prevIndex != -1) {
15 minDistance = min(minDistance, i - prevIndex);
16 }
17 // Update previous index to current position
18 prevIndex = i;
19 }
20 }
21 }
22 // Case 2: When word1 and word2 are different
23 else {
24 int word1Index = -1; // Track the most recent position of word1
25 int word2Index = -1; // Track the most recent position of word2
26
27 for (int i = 0; i < n; ++i) {
28 // Update position if we find word1
29 if (wordsDict[i] == word1) {
30 word1Index = i;
31 }
32 // Update position if we find word2
33 if (wordsDict[i] == word2) {
34 word2Index = i;
35 }
36 // If both words have been found at least once, calculate distance
37 if (word1Index != -1 && word2Index != -1) {
38 minDistance = min(minDistance, abs(word1Index - word2Index));
39 }
40 }
41 }
42
43 return minDistance;
44 }
45};
46
1/**
2 * Finds the shortest distance between two words in a word dictionary.
3 * Handles the case where word1 and word2 can be the same word.
4 *
5 * @param wordsDict - Array of words to search through
6 * @param word1 - First target word
7 * @param word2 - Second target word
8 * @returns The minimum distance between occurrences of word1 and word2
9 */
10function shortestWordDistance(wordsDict: string[], word1: string, word2: string): number {
11 // Initialize result with maximum possible distance
12 let minDistance: number = wordsDict.length;
13
14 if (word1 === word2) {
15 // Case: Both words are the same, find minimum distance between consecutive occurrences
16 let previousIndex: number = -1;
17
18 for (let currentIndex = 0; currentIndex < wordsDict.length; currentIndex++) {
19 if (wordsDict[currentIndex] === word1) {
20 // If we've seen this word before, calculate distance
21 if (previousIndex !== -1) {
22 minDistance = Math.min(minDistance, currentIndex - previousIndex);
23 }
24 // Update previous occurrence index
25 previousIndex = currentIndex;
26 }
27 }
28 } else {
29 // Case: Words are different, find minimum distance between any occurrences
30 let word1Index: number = -1;
31 let word2Index: number = -1;
32
33 for (let currentIndex = 0; currentIndex < wordsDict.length; currentIndex++) {
34 // Update index when we find word1
35 if (wordsDict[currentIndex] === word1) {
36 word1Index = currentIndex;
37 }
38 // Update index when we find word2
39 if (wordsDict[currentIndex] === word2) {
40 word2Index = currentIndex;
41 }
42 // If both words have been found at least once, calculate distance
43 if (word1Index !== -1 && word2Index !== -1) {
44 minDistance = Math.min(minDistance, Math.abs(word1Index - word2Index));
45 }
46 }
47 }
48
49 return minDistance;
50}
51
Time and Space Complexity
Time Complexity: O(n)
, where n
is the length of the array wordsDict
.
The algorithm iterates through the wordsDict
array exactly once in both cases (whether word1 == word2
or word1 != word2
). In each iteration, it performs constant-time operations such as comparisons, assignments, and calculating the minimum value. Therefore, the overall time complexity is linear with respect to the size of the input array.
Space Complexity: O(1)
.
The algorithm uses only a constant amount of extra space regardless of the input size. It maintains a few integer variables (ans
, i
, j
, k
) to track positions and the minimum distance. No additional data structures that grow with the input size are created, resulting in constant space complexity.
Common Pitfalls
Pitfall 1: Not Handling the Same Word Case Correctly
A critical mistake is treating the problem as if it always involves two different words. When word1 == word2
, using the same tracking logic as for different words will result in a distance of 0, since you'd be comparing the same occurrence with itself.
Incorrect approach:
# This fails when word1 == word2
last_pos1 = -1
last_pos2 = -1
for i, word in enumerate(wordsDict):
if word == word1:
last_pos1 = i
if word == word2:
last_pos2 = i
if last_pos1 != -1 and last_pos2 != -1:
min_distance = min(min_distance, abs(last_pos1 - last_pos2))
# Returns 0 when word1 == word2 (wrong!)
Solution: Use separate logic branches. When the words are the same, track consecutive occurrences:
if word1 == word2:
prev_index = -1
for i, word in enumerate(wordsDict):
if word == word1:
if prev_index != -1:
min_distance = min(min_distance, i - prev_index)
prev_index = i
Pitfall 2: Using elif Instead of if for Word Matching
When word1 != word2
, a word in the array might need to be checked against both target words. Using elif
would skip the second check if the first matches, potentially missing valid updates.
Incorrect approach:
# This misses cases where a word could match both conditions if word == word1: word1_index = current_index elif word == word2: # Wrong! Should be 'if' word2_index = current_index
Solution: Use two independent if
statements to ensure both conditions are checked:
if word == word1: word1_index = current_index if word == word2: # Separate if statement word2_index = current_index
Pitfall 3: Incorrect Distance Calculation for Same Word
When finding the distance between two occurrences of the same word, forgetting to update the previous index after calculating the distance leads to incorrect comparisons in subsequent iterations.
Incorrect approach:
if word1 == word2:
prev = -1
for i, word in enumerate(wordsDict):
if word == word1 and prev != -1:
min_distance = min(min_distance, i - prev)
# Forgot to update prev = i here!
Solution: Always update the previous index after finding a match, regardless of whether a distance was calculated:
if word == word1:
if prev != -1:
min_distance = min(min_distance, i - prev)
prev = i # Always update for the next comparison
Is the following code DFS or BFS?
void search(Node root) { if (!root) return; visit(root); root.visited = true; for (Node node in root.adjacent) { if (!node.visited) { search(node); } } }
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!