[Typescropt]无重复字符的最长子串
function lengthOfLongestSubstring(s: string): number {
let res = 0;
const window = new Map();
let left = 0;
let right = 0;
while (right < s.length) {
let rightChar = s[right];
right++;
// 进行窗口内数据的一系列更新
window.set(rightChar, (window.get(rightChar) || 0) + 1);
while(window.get(rightChar) > 1){
let leftChar = s[left];
left++;
// 进行窗口内数据的一系列更新
window.set(leftChar, window.get(leftChar) - 1);
}
// 在这里更新答案
res = Math.max(res, right - left);
}
return res;
}
思路
这道题目是寻找一个字符串s中最长不含重复字符的子串的长度。这是一种典型的滑动窗口问题,可以通过使用双指针(在这里用left和right表示)来解决。以下是算法的详细思路:
-
初始化:
res用于存储最长子串的长度。window是一个Map对象,用于存储当前窗口内字符的出现次数。
-
滑动窗口:
- 使用
right指针从左到右遍历字符串s,扩展窗口的右边界。
- 使用
-
更新窗口:
- 每扩展一位,将
s[right]的字符计数加一,使用window.set(rightChar, (window.get(rightChar) || 0) + 1)。
- 每扩展一位,将
-
处理重复字符:
- 如果当前字符在窗口中已经存在(即
window.get(rightChar) > 1),则需要移动left指针,缩小窗口的左边界,直到该字符的计数为1。
- 如果当前字符在窗口中已经存在(即
-
移动
left指针:- 移动
left指针时,将s[left]的字符计数减一,使用window.set(leftChar, window.get(leftChar) - 1)。
- 移动
-
更新最长长度:
- 在每次窗口扩展后,更新
res的值,使用res = Math.max(res, right - left)。这里的right - left实际上是当前窗口的长度,也就是不包含重复字符的子串的长度。
- 在每次窗口扩展后,更新
-
循环直至结束:
- 重复步骤3到6,直到
right指针遍历完整个字符串s。
- 重复步骤3到6,直到
-
返回结果:
- 返回
res,即最长不含重复字符子串的长度。
- 返回
这个算法的时间复杂度是O(n),其中n是字符串s的长度,因为每个字符最多被访问两次(一次由right指针访问,一次或零次由left指针访问)。空间复杂度是O(k),其中k是字符集的大小,因为window Map最多存储所有可能的不同字符及其计数。