给定一个字符串 s
,请你找出其中不含有重复字符的 最长
子串
的长度。
示例 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
由英文字母、数字、符号和空格组成
因为s由英文字母、数字、符号和空格组成,符合ASCII码,故采用ASCII码大小的数组,使用ASCII码为下标,记录每个字符出现的最后位置。并在每次循环的开始,将left更新为上一次该字符出现的位置+1。
滑动窗口算法的基本原理:
-
初始化窗口:定义两个指针,通常是
left
和right
,并初始化为字符串或数组的起始位置。 -
滑动窗口:
right
指针逐个增加,尝试扩大窗口,同时更新解的答案。 -
更新解的答案:当满足题目条件时,我们需要更新当前的最优解。
-
收缩窗口:如果当前窗口不满足题目的条件,移动
left
指针缩小窗口,直到满足条件为止。
示例分析:
以题目"abcabcbb"
为例,详细步骤如下:
-
初始化:
left = 0, right = 0, maxLen = 0, charIndex[] = {-1, -1, -1, ...}
-
right
逐个增加:s[0] = 'a'
,charIndex['a'] = -1
,更新为charIndex['a'] = 0
,窗口长度为1
,maxLen = 1
。s[1] = 'b'
,charIndex['b'] = -1
,更新为charIndex['b'] = 1
,窗口长度为2
,maxLen = 2
。s[2] = 'c'
,charIndex['c'] = -1
,更新为charIndex['c'] = 2
,窗口长度为3
,maxLen = 3
。s[3] = 'a'
,charIndex['a'] = 0
,左指针移动到1
,窗口变为"bca"
,窗口长度为3
,maxLen
保持不变。s[4] = 'b'
,charIndex['b'] = 1
,左指针移动到2
,窗口变为"cab"
,窗口长度为3
,maxLen
保持不变。s[5] = 'c'
,charIndex['c'] = 2
,左指针移动到3
,窗口变为"abc"
,窗口长度为3
,maxLen
保持不变。s[6] = 'b'
,charIndex['b'] = 1
,左指针移动到4
,窗口变为"bca"
,窗口长度为3
,maxLen
保持不变。s[7] = 'b'
,charIndex['b'] = 1
,左指针移动到5
,窗口变为"cab"
,窗口长度为3
,maxLen
保持不变。
最终结果为3
。
int lengthOfLongestSubstring(char *s) {// 使用一个数组来存储每个字符最后出现的位置int charIndex[128]; // 假设字符集为ASCII,有128个字符memset(charIndex, -1, sizeof(charIndex)); // 初始化为-1int left = 0; // 左指针,用于标记窗口的开始位置int maxLen = 0; // 最长子串的长度int len = strlen(s);for (int right = 0; right < len; right++) {// 如果字符已经在窗口中,并且其位置在左指针之后if (charIndex[s[right]] >= left) {// 移动左指针到重复字符的下一个位置left = charIndex[s[right]] + 1;}// 更新每个字符的位置,每个字符初始left都是0charIndex[s[right]] = right;// 计算当前窗口的长度.正常是位置,如果该字符已经出现过了,就会更新left,减去的就是上一次出现的位置。int windowLen = right - left + 1;// 更新最长子串的长度if (windowLen > maxLen) {maxLen = windowLen;}}return maxLen;
}
right
指针逐个增加,尝试扩大窗口。- 检查新加入的字符
s[right]
是否已经在当前窗口中。 - 如果已经在窗口中并且其位置在
left
指针之后,更新left
指针的位置。 - 更新
charIndex
数组中s[right]
字符的位置为right
。 - 计算当前窗口的长度
windowLen
,并与maxLen
比较,更新最长子串的长度。