1. Force buckle C + + source code
class Solution { public: int lengthOfLongestSubstring(string s) { map<char, int> hash; int ans = 0; int i = 0; int n = s.length(); for (int j = 0; j < n; j++) { if (hash.find(s[j]) != hash.end()) { i = max(hash.find(s[j])->second + 1, i); } hash[s[j]] = j; ans = max(ans, j - i + 1); } return ans; } };
2. Problem solving
(1) Problem solving idea: sliding window
We might as well take the string abcabcbb in example 1 as an example to find the longest substring starting from each character and not containing repeated characters, and the longest string is the answer. For the string in example 1, we list these results, where the selected character and the longest string are represented in parentheses:
- The longest string starting with a(b)cabcbb is a(bca)bcbb;
- With ab © The longest string starting from abcbb is ab(cab)cbb;
- The longest string starting with abc(a)bcbb is abc(abc)bb;
- The longest string starting with abca(b)cbb is abca(bc)bb;
- Abcab © The longest string starting from bb is abcab(cb)b;
- The longest string starting with abcabc(b)b is abcabc(b)b;
- The longest string starting with abcabcb(b) is abcabcb(b).
What did you find? If we enumerate the starting position of the substring incrementally, the ending position of the substring is also incremented! The reason for this is that suppose we select the k-th character in the string as the starting position, and get that the end position of the longest substring without repeated characters is rk. Then, when we select the K + 1st character as the starting position, it is obvious that the characters from k+1 to rk are not repeated at first, and since the original k-th character is missing, we can try to continue to increase rk until there are repeated characters on the right.
In this way, we can use the sliding window to solve this problem:
- We use two pointers to represent the left and right boundaries of a substring (or window) in the string. The left pointer represents the "starting position of enumeration substring" in the above, and the right pointer is rk in the above;
- In each step of operation, we will move the left pointer one grid to the right, indicating
We start to enumerate the next character as the starting position, and then we can constantly move the right pointer to the right, but we need to ensure that there are no duplicate characters in the substring corresponding to the two pointers. After the move, the substring corresponds to
The longest substring that starts with the left pointer and does not contain duplicate characters. We record the length of this substring; - After enumeration, the length of the longest substring we find is the answer.
Determine duplicate characters
In the above process, we also need to use a data structure to judge whether there are duplicate characters. The common data structure is hash table (i.e. map in C + +). When the left pointer moves to the right, we remove a character from the hash table. When the right pointer moves to the right, we add a character to the hash table.
(2) Method 1: sliding window
We use the hash table to store the characters in the current window [i, j) (initially j = i). Then we slide the index j to the right. If it is not in the hash table, we will continue to slide j until s[j] It already exists in the hash table. At this time, the longest substring we find without duplicate characters will start with index i. if we do this for all i, we can get the answer. That is, when s[j] already exists in the hash table, empty the hash table, move i back one bit, and then repeat the above operation.
map<char, int> hash;//Define a hash table int ans = 0; int i = 0;//Left pointer int j = 0;//Right pointer int n = s.length();//String length while (i < n && j < n) { //Usage of hash.find(): //Keyword query. If it is found, it returns the iterator pointing to the keyword; otherwise, it returns the iterator pointing to end //hash.end(), pointing to the next position of the last element if (hash.find(s[j]) == hash.end()) { //Hash [s [J + +] = J; / / equivalent to hash[s[j]]=j;j++; j autoincrement must precede j-i in the next statement hash[s[j]] = j;//Add the element from the right pointer j to the hash table j++; ans = max(ans, j - i);//Maximum function max(,) } else { //hash.erase(s[i + +]); / / delete the elements in the hash table according to the key value. This statement is equivalent to hash.erase(s[i]);i + +; slide one bit to the right each time (this can be improved, see method 3) hash.erase(s[i]); //Delete the element pointed to by the left pointer i i++; } } return ans;
(3) Method 2: optimized sliding window
Based on the previous method, when we find duplicate characters, we can immediately skip the window. That is, if s[j] has characters that repeat with J 'in the range of [i, J], we don't need to gradually increase ii. We can directly skip all elements in the range of [i, J'] and change i to j '+ 1.
map<char, int> hash; int ans = 0; int n = s.size(); for (int i = 0, j = 0; j < n; j++) { if (hash.find(s[j]) != hash.end()) { //i = max (hash. Find (s [J]) - > second + 1, i); / / when a duplicate character is found, i directly jumps to the next bit of the duplicate character, which improves the method of sliding the window one character by one in method 2 //i = hash. Find (s [J]) - > second + 1; / / error. Compare with i to get the maximum value //max(,) is required because the existing elements are not cleared and still exist in the hash table //If this element is before the pointer i, i will jump to the front again, the length (j-i+1) will be long, and the result will be wrong } hash[s[j]] = j; ans = max(ans, j - i + 1); } return ans;
3.VS runnable source code
#include<stdio.h> #include<stdlib.h> #include<iostream> #include<map> #pragma warning(disable:4996) using namespace std; class Solution { public: int lengthOfLongestSubstring(string s) { //Method 2: sliding window //We use a hash table to store characters in the current window [i, j) (initially j = i). //Then we slide the index j to the right, and if it is not in the hash table, we will continue to slide j. //Until s[j] already exists in the hash table. //At this point, the longest substring we find without duplicate characters will start with index i. //If we do this for all i, we can get the answer. //That is, when s[j] already exists in the hash table, empty the hash table, //Then move i backward one bit and repeat the above operation. //Map < char, int > hash; / / define a hash table //int ans = 0; //int i = 0; / / left pointer //int j = 0; / / right pointer //int n = s.length(); / / string length //while (i < n && j < n) { // //Usage of hash.find(): // //Keyword query. If it is found, it returns the iterator pointing to the keyword; otherwise, it returns the iterator pointing to end // //hash.end(), pointing to the next position of the last element // if (hash.find(s[j]) == hash.end()) { // //Hash [s [J + +] = J; / / equivalent to hash[s[j]]=j;j++; j autoincrement must precede j-i in the next statement // hash[s[j]] = j; / / add the element from the right pointer j to the hash table // j++; // ans = max(ans, j - i); / / maximum function max(,) // } // else { // //hash.erase(s[i + +]); / / delete the elements in the hash table according to the key value. This statement is equivalent to hash.erase(s[i]);i + +; slide one bit to the right each time (this can be improved, see method 3) // hash.erase(s[i]); / / delete the element pointed to by the left pointer I // i++; // } //} //return ans; //Write it yourself: /*map<char, int> hash; int ans = 0; int i = 0; int j = 0; int n = s.length(); while (i < n && j < n) { if (hash.find(s[j]) == hash.end()) { hash[s[j]] = j; j++; ans = max(ans, j - i); } else { hash.erase(s[i]); i++; } } return ans;*/ //Method 3: optimized sliding window //Based on the previous method, when we find duplicate characters, we can immediately skip the window. //That is, if s[j] has a character repeated with j 'in the range of [i, j), //We don't need to gradually increase ii. //We can directly skip all elements in the range of [i, J '] and change i to j' + 1. map<char, int> hash; int ans = 0; int n = s.size(); for (int i = 0, j = 0; j < n; j++) { if (hash.find(s[j]) != hash.end()) { //i = max(hash.find(s[j])->second + 1, i); // When a duplicate character is found, I directly jumps to the next bit of the duplicate character, which improves the method of sliding the window one character by one in method 2 //i = hash.find(s[j])->second + 1;// Error, to compare with I to the maximum value //max(,) is required because the existing elements are not cleared and still exist in the hash table //If this element is before the pointer i, i will jump to the front again, the length (j-i+1) will be long, and the result will be wrong } hash[s[j]] = j; ans = max(ans, j - i + 1); } return ans; //Write it yourself: /*map<char, int> hash; int ans = 0; int i = 0; int n = s.length(); for (int j = 0; j < n; j++) { if (hash.find(s[j]) != hash.end()) { i = max(hash.find(s[j])->second + 1, i); } hash[s[j]] = j; ans = max(ans, j - i + 1); } return ans;*/ } }; int main() { cout << "Please enter a string:"; string s; cin >> s; Solution test; int ret=test.lengthOfLongestSubstring(s); cout << "The longest substring length without duplicate characters is:" <<ret; system("pause"); return 0; }