给定一个字符串 s ,请你找出其中不含有重复字符的 最长
子串
的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104s 由英文字母、数字、符号和空格组成因为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)); // 初始化为-1
-
- int 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都是0
- charIndex[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比较,更新最长子串的长度。