题目描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: s = ""
输出: 0
提示:
- 0 <= s.length <= 5 * 104
- s 由英文字母、数字、符号和空格组成
方法一:滑动窗口(双指针),控制右指针
int lengthOfLongestSubstring(string s)
{
unordered_set<char> hashset;
hashset.insert(s[0]);
unsigned maxLength = 1;
unsigned int left = 0; // 用来标识当前无重复字符串的起始位置
for (unsigned right = 1; right < s.size(); right++)
{
if (hashset.find(s[right]) == hashset.end()) // hashset 不存在当前字符
{
hashset.insert(s[right]);
maxLength = max(maxLength, right - left + 1);
}
else
{
if (hashset.size() == 1) // hashset 中只有一个字符,且和下一个重复
{
left++;
continue;
}
hashset.erase(s[left++]); // 滑动窗口左侧删除一个元素,并将左侧前进1
while (left < right && hashset.find(s[right]) != hashset.end()) // 重复字符还未删除
hashset.erase(s[left++]); // 去除无重复字符串(滑动窗口)最左侧字符
hashset.insert(s[right]); // 窗口内重复元素已经删除,将新元素插入窗口
}
}
return maxLength;
}
方法二:滑动窗口(双指针),控制左指针
int lengthOfLongestSubstring2(string s)
{
unordered_set<char> hashset;
int right = -1; // 相当于滑动窗口右边边界。初始时滑动窗口还不存在,为-1。
int maxLength = 0;
for (int left = 0; left < s.size(); left++)
{
if (left != 0)
hashset.erase(s[left - 1]); // 滑动窗口左侧向右移动一个位置
// 只有当滑动窗口下一个元素不在滑动窗口内时,才加入滑动窗口,并且滑动窗口右侧扩1
while (right + 1 < s.size() && !hashset.count(s[right + 1]))
{
hashset.insert(s[right + 1]);
right++;
}
maxLength = max(maxLength, right - left + 1);
}
return maxLength;
}
相比控制右指针,控制左指针性能相对会低一点点