3. Longest Substring Without Repeating Characters
How to identify substrings without repeating characters
Problem statement
Given a string s
, find the length of the longest substring without repeating characters.
Example 1
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with a length of 3.
Example 2
Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with a length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
Constraints
0 <= s.length <= 5 * 10^4
.s
consists of English letters, digits, symbols and spaces.
Solution: Store the position of the visited characters
One way of checking the repetition of the characters is by using a map to store their indices. For example:
last_visit[s[i]] = i
You might want to find every substring of nonrepeating characters in the string s
, then identify the longest one among them.
The character you are checking its repetition and computing the length should be done within its substring;
The map should always update the latest visited index of a character; and
The starting index of a substring is also updated when repetition happens.
Example 1
For the string s = "abcabcbb"
:
When you visit the second letter
'a'
, the first substring is formed"abc"
, the next substring starts from the second letter'a'
:start = 3
,last_visit['a']
is updated to be3
.When you visit the second letter
'b'
, itslast_visit['b']
is updated to be4
.Repetition is found when you visit the third letter
'b'
, the second substring"abc"
is formed. The nextstart = 6
;last_visit['b'] = 6
.The fourth letter
'b'
causes a repetition and forms a one-letter substring"b"
.The string
s
ends and form another one-letter substring"b"
.
Code
#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> last_visit;
int maxLen = 0;
int start = -1;
for (int i = 0; i < s.length(); i++) {
auto it = last_visit.find(s.at(i));
if (it != last_visit.end()) {
start = max(start, it->second);
it->second = i;
} else {
last_visit.insert({s.at(i), i});
}
maxLen = max(maxLen, i - start);
}
return maxLen;
}
int main() {
cout << lengthOfLongestSubstring("abcabcbb") << endl;
cout << lengthOfLongestSubstring("bbbbb") << endl;
cout << lengthOfLongestSubstring("pwwkew") << endl;
}
Output:
3
1
3
Complexity
Runtime:
O(N)
, whereN = s.length
.Extra space:
O(N)
.
Implementation notes
You can initialize the
start
index of the substrings with-1
to deal with the boundary cases.As a best practice, when you check if a map contains a key and retrieve its value, use an iterator and
find()
like the above solution. DO NOT implement as follow
if (last_visit.find(s.at(i)) != last_visit.end()) {
start = max(start, last_visit[s.at(i)]);
}
Because the operator []
might perform an additional find()
.
What is your approach? The problem was picked from leetcode.com. You can submit your solution in any programming language and check the performance.
Thanks for reading. Feel free to share your thought about my content and check out my FREE book 10 Classic Coding Challenges.