Longest Substring Without Repeating Characters
2024年2月3日 2024年2月3日
LeetCode - Longest Substring Without Repeating Characters
写在前面
ac一道找找状态
思路
只需要给出无重复的最大字符串长度, 而不用输出字符串内容; 该长度的字符串可以不止一个
遍历一次输入字符串, 遍历时更新无重复的子字符串, 比较子串和目前最大无重复串的长度, 决定是否更新最大无重复子串
解答
存在测试用例: 字符串为空
第一版
- 使用curStart和curEnd定位当前无重复子串
- 使用max保存当前最大无重复子串
- 若在当前子串中查找到重复字符, 其下一位置作为子串的新起点
- 增加当前子串长度时, 已纳入当前字符
使用左开右闭区间 [curStart, curEnd)
描述当前无重复子串
1class Solution { 2public: 3 int lengthOfLongestSubstring(string s) { 4 auto n = s.size(); 5 int curStart = 0, curEnd = 1; 6 string max = s.substr(0, 1); 7 8 for (; curEnd < n; ++curEnd) 9 { 10 auto res = s.substr(curStart, curEnd - curStart).find(s[curEnd]); 11 12 if (res != string::npos) 13 { 14 curStart += res + 1; 15 } 16 else 17 { 18 if (curEnd + 1 - curStart > max.size()) 19 { 20 max = s.substr(curStart, curEnd + 1 - curStart); 21 } 22 } 23 } 24 return max.size(); 25 } 26};
优化点
- 字符串查找可使用无序容器
- 只需要最大无重复字符串的长度, 无需保存其内容
- substr的处理包容了字符串为空的情形
第二版
-
使用unordered_map: 移除无效字符
1class Solution { 2public: 3 int lengthOfLongestSubstring(string s) { 4 auto n = s.size(); 5 unordered_map<char, int> um; 6 int start = 0, max = 0; 7 8 for (auto i = 0; i < n; ++i) 9 { 10 auto res = um.find(s[i]); 11 if (res != um.end()) 12 { 13 for (auto j = start; j < res->second; ++j) 14 { 15 um.erase(s[j]); 16 } 17 18 start = res->second + 1; 19 res->second = i; 20 } 21 else 22 { 23 um.insert({s[i], i}); 24 if (um.size() > max) 25 { 26 max = um.size(); 27 } 28 } 29 } 30 return max; 31 } 32};
-
使用unordered_set
当集合中存在当前字符时, 先于字符加入集合的需要删除, 后于字符加入集合的则保留, 无明显的手段判断先后顺序选择遍历字符串, 从前往后删字符, 如果不再查找得到, 则刚刚好删除了包括该字符在内的所有前缀
1class Solution { 2public: 3 int lengthOfLongestSubstring(string s) { 4 auto n = s.size(); 5 unordered_set<char> us; 6 int start = 0, max = 0; 7 8 for (auto i = 0; i < n; ++i) 9 { 10 if (us.find(s[i]) != us.end()) 11 { 12 do { 13 us.erase(s[start++]); 14 } while (us.find(s[i]) != us.end()); 15 16 us.insert(s[i]); 17 } 18 else 19 { 20 us.insert(s[i]); 21 if (us.size() > max) 22 { 23 max = us.size(); 24 } 25 } 26 } 27 return max; 28 } 29};
-
使用unordered_map: 更新下标
判断字符重复的标准为: 已有关键字, 且在当前子串序列中1class Solution { 2public: 3 int lengthOfLongestSubstring(string s) { 4 auto n = s.size(); 5 unordered_map<char, int> um; 6 int start = 0, maxLen = 0; 7 8 for (int i = 0; i < n; ++i) 9 { 10 if (um.count(s[i]) && um[s[i]] >= start) 11 { 12 start = um[s[i]] + 1; 13 um[s[i]] = i; 14 15 } 16 else 17 { 18 um[s[i]] = i; 19 maxLen = max(maxLen, i + 1 - start); 20 } 21 } 22 return maxLen; 23 } 24};