3.无重复字符的最长子串
- 给定一个字符串
s
,请你找出其中不含有重复字符的 最长子串 的长度。
方法二:滑动窗口
- 设置滑动窗口
(left, right]
,left
指向初始元素的前一位置,right
指向末尾元素。初始值left=1,right=0
。 - 依次扩大
right
的值来扩大滑动窗口,直到滑动窗口中出现重复的元素。 - 一旦子串中出现重复元素,或
right
已经遍历字符串所有内容时,滑动窗口(left, rigth]
是最长无重复子串,长度为right - left-1
,使用 Longest 记录最长无重复子串的最大长度。 - 此时,已经得到了以
left
指向的元素为初始位置的无重复子串,left
右移一位,找下一个元素为初始元素的无重复子串。 - 一旦左边界越过右边界,则遍历结束。
该方法的主要思想是:假设我们选择字符串中的第 k k k 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 r k r_k rk。那么当我们选择第 k + 1 k+1 k+1 个字符作为起始位置时,首先从 k + 1 k+1 k+1 到 r k r_k rk 的字符显然是不重复的,并且由于少了原本的第 k k k 个字符,我们可以尝试继续增大 r k r_k rk,直到右侧出现了重复字符为止。
判断重复字符
使用 unordered_set
来判断 是否有重复字符,便于判断哈希集合中是否存在某字符。
代码实现
int lengthOfLongestSubstring(string s) {
//使用 哈希集合,记录每个字符是否出现过
unordered_set<char> ItemOfSub;
int nSize = s.size();
int Longest = 0; //记录最长子串的长度
//设置滑动窗口的左右边界,left指向初始元素的前一位置,right指向末尾元素
int left = -1, right = 0;
while (left < right) {
//遍历的第一步时,集合中没有元素,此时 left 指向 -1,不需要删除元素
if (left >= 0) {
ItemOfSub.erase(s[left]);
}
while (right < nSize && ItemOfSub.count(s[right]) == 0) {
//子串中不包含 右指针 指向的元素
ItemOfSub.insert(s[right]);
right++;
}
//一旦子串中出现重复元素,或 right 已经遍历字符串所有内容
//(left, rigth]是最长无重复子串,长度为right - left-1
Longest = max(Longest, right - left-1);
//此时,已经得到了以 left 指向的元素为初始位置的无重复子串
//left 右移一位,找下一个元素为初始元素的无重复子串
left++;
}
return Longest;
}
时间复杂度: O ( N ) O(N ) O(N), N N N 是字符串的长度。
空间复杂度: O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣), Σ \Sigma Σ 表示字符集,即字符串中可以出现的字符。