Longest Substring Without Repeating Characters
Problem
Given a string s
, find the length of the longest substring without repeating characters.
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Solution
The main idea is to use an imaginary sliding window.
Until we see a repeated character, we just can keep expanding the window.
However, once we see a repeated character, the starting point of the window needs to be moved to the right until the last occurrence of the repeated character is no longer in the window.
\[\fbox{abcde} \mbox{fd} \implies \fbox{abcdef} \mbox{d} \implies \mbox{abcd} \fbox{efd}\]So, we should to keep track of the last occurrence of each character.
I will be using a HashMap<Character, Integer>
to do this, where each character is mapped to its index of last occurrence.
HashMap<Character, Integer> seen = new HashMap<>();
int maxLen = 0; // Max found so far
int curLen = 0; // Size of current window
for (int j = 0; j < s.length(); j++) {
Character c = s.charAt(j);
if (seen.containsKey(c)) { // Found a repeated character
int i = seen.get(c); // Retrieve index of last occurrence
if (j - curLen > i) { // If last occurrence is not within window
curLen++;
} else {
curLen = j - (i + 1) + 1; // Calculate new window size
}
seen.replace(c, j); // Update last occurrence
} else {
curLen++; // Expand window
seen.put(c, j); // Record last occurrence
}
maxLen = Math.max(maxLen, curLen);
}
return maxLen;
Everything is straightforward except for:
if (j - curLen > i) { // If last occurrence is not within window
curLen++;
} else {
curLen = j - (i + 1) + 1; // Calculate new window size
}
What is the if
statement doing?
Take the example of abbcda
. When we see the last a
at index 5, the window looks like
The window should now ignore everything before the second b
, but the HashMap
still has a -> 0
in it.
Calculating j - (i + 1) + 1
will give us the wrong window of
so we have to make the window ignore everything outside of current window.