Use HashMap to store counts of letters
Two points we should be noticed:
-
The length of substring should be
(right - left) + 1, as one side must be counted. -
We must decrese the number in the
countsfirst, and then slide the left window, or we must decrese the wrong one, please compare between Wrong and Correct.Wrong
left++; counts[s[left]]--;Correct
counts[s[left]]--; left++;
The full code see:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0;
int longest = 0;
char c;
map<char, int> counts;
// for loop to slide the right side of window.
for (int right = 0; right < s.size(); right++) {
c = s[right];
if (counts.find(c) == counts.end()) {
counts[c] = 0;
}
counts[c]++;
// slide the left side of window to meet the requirements,
// here is "Without Repeating Characters".
for (auto iter = counts.begin(); iter != counts.end(); ++iter) {
if (iter->second > 1) {
counts[s[left]]--;
left++;
break;
}
}
// compare to result.
longest = max(longest, right - left + 1);
}
return longest;
}
};
See also: An Introduction to Sliding Window Algorithms
Use HashMap to store index of letters
Points that should be noticed:
-
The whole string without repeating, that will not meet the condition: letter is indexed already.
" ""au"
// no duplicated if (indices.find(l) != indices.end()) { left = indices[l] + 1; longest = max(longest, right - left + 1); }In those cases longest will be 0, if this is the only one block to compute the
longest.Move compute the
longestout of the if block, the problem should be sloved.// no duplicated if (indices.find(l) != indices.end()) { left = indices[l] + 1; } longest = max(longest, right - left + 1); -
The
leftmay go backward from a HashTable, and that must be avoid.- “abba”
if (indices.find(l) != indices.end() && indices[l] + 1 > left) { left = indices[l] + 1; } longest = max(longest, right - left + 1);And notice that
+1must exists in the condition, the WRONG edition:if (indices.find(l) != indices.end() && indices[l] > left) { left = indices[l] + 1; } longest = max(longest, right - left + 1);
Finally code:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0;
int longest = 0;
map<char, int> indices;
for (auto right = 0; right < s.size(); right++) {
char l = s[right];
if (indices.find(l) != indices.end() && indices[l] + 1 > left) {
left = indices[l] + 1;
}
longest = max(longest, right - left + 1);
indices[l] = right;
}
return longest;
}
};
Full with failed:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0;
int longest = 0;
map<char, int> indices;
for (auto right = 0; right < s.size(); right++) {
char l = s[right];
/*
// failed on string without repeating: " " "au"
if (indices.find(l) != indices.end()) {
left = indices[l] + 1;
longest = max(longest, right - left + 1);
}
*/
/*
// failed on left go backward: "abba"
if (indices.find(l) != indices.end()) {
left = indices[l] + 1;
}
longest = max(longest, right - left + 1);
*/
if (indices.find(l) != indices.end() && indices[l] + 1 > left) {
left = indices[l] + 1;
}
longest = max(longest, right - left + 1);
indices[l] = right;
}
return longest;
}
};
Optimization: use the unordered_map to instead map.
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0;
int longest = 0;
unordered_map<char, int> indices;
for (auto right = 0; right < s.size(); right++) {
char l = s[right];
if (indices.find(l) != indices.end() && indices[l] + 1 > left) {
left = indices[l] + 1;
}
longest = max(longest, right - left + 1);
indices[l] = right;
}
return longest;
}
};