题目描述:
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度
题目分析:
可以通过使用滑动窗口的方法来解决。滑动窗口是一种数组/字符串问题中常用的抽象概念,它表示维护一个固定长度的窗口,随着遍历的进行在数组或字符串上滑动。
我们去遍历这个字符串S,每当遍历一个字符,把它放入一个容器中,在放入之前会判断这个字符是否已经存在了,如果不存在直接放入,字串长度+1;
如果当前字符已经存在了,我们需要把这个已经存在的字符上一次插入位置之前的字符全部移除掉,这样不重复的字串会重新开始计算。
每遍历一个判断一次最长字串的长度。
编码步骤:
- 初始化两个索引来表示子串的开始和结束位置,以及一个用于存储最长子串长度的变量。
- 使用一个集合来存储当前窗口内的字符,以便于快速检查字符是否重复。
- 遍历字符串,将遇到的字符添加到集合内中,并更新窗口的结束位置。
- 如果当前字符已存在(即重复),则移动窗口的开始位置,直到该字符被移出窗口。
- 在每次移动窗口时,更新最长子串长度的变量。
- 重复上述步骤,直到遍历完整个字符串。
完整C++代码:
变量start叫窗口的开始位置,用大白话讲是当前子串在s中的起始索引
#include <iostream>
#include <string>
#include <unordered_set>
int lengthOfLongestSubstring(std::string s) {
std::unordered_set<char> char_set; // 用于存储当前窗口内的字符
int max_length = 0; // 不含重复字符的最长子串的长度
int start = 0; // 窗口的开始位置
for (int end = 0; end < s.length(); ++end) {
while (char_set.find(s[end]) != char_set.end()) {
// 字符已存在,移除字符,直到把存在这个字符移除为止
char_set.erase(s[start]);
start++;
}
char_set.insert(s[end]);
max_length = std::max(max_length, end - start + 1);
}
return max_length;
}
int main() {
std::string s = "abcabcbb";
std::cout << "The length of the longest substring without repeating characters is " << lengthOfLongestSubstring(s) << std::endl;
return 0;
}
关键代码详细解释:
while (char_set.find(s[end]) != char_set.end()) {
// 字符已存在,移除字符,直到把存在这个字符移除为止
char_set.erase(s[start]);
start++;
}
char_set.insert(s[end]);
max_length = std::max(max_length, end - start + 1);
比如字符串是:abcbdpoejelmfn...
当遍历前3个字符时没有任何问题,不会触发while的判断条件一直为假。
当遍历第四个字符b时,while的判断条件会为true,进去。
当循环第一次时start=0,移除了字符a;
当循环第二次时start=1,移除字符b;
第三次判断时,while条件为false;
依次遍历,循环处理保证字串中不出现重复的字串。
每遍历一个字符都会记录最长长度
测试用例
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc"
,所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成