[Typescropt]无重复字符的最长子串

64 阅读2分钟

[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中最长不含重复字符的子串的长度。这是一种典型的滑动窗口问题,可以通过使用双指针(在这里用leftright表示)来解决。以下是算法的详细思路:

  1. 初始化

    • res用于存储最长子串的长度。
    • window是一个Map对象,用于存储当前窗口内字符的出现次数。
  2. 滑动窗口

    • 使用right指针从左到右遍历字符串s,扩展窗口的右边界。
  3. 更新窗口

    • 每扩展一位,将s[right]的字符计数加一,使用window.set(rightChar, (window.get(rightChar) || 0) + 1)
  4. 处理重复字符

    • 如果当前字符在窗口中已经存在(即window.get(rightChar) > 1),则需要移动left指针,缩小窗口的左边界,直到该字符的计数为1。
  5. 移动left指针

    • 移动left指针时,将s[left]的字符计数减一,使用window.set(leftChar, window.get(leftChar) - 1)
  6. 更新最长长度

    • 在每次窗口扩展后,更新res的值,使用res = Math.max(res, right - left)。这里的right - left实际上是当前窗口的长度,也就是不包含重复字符的子串的长度。
  7. 循环直至结束

    • 重复步骤3到6,直到right指针遍历完整个字符串s
  8. 返回结果

    • 返回res,即最长不含重复字符子串的长度。

这个算法的时间复杂度是O(n),其中n是字符串s的长度,因为每个字符最多被访问两次(一次由right指针访问,一次或零次由left指针访问)。空间复杂度是O(k),其中k是字符集的大小,因为window Map最多存储所有可能的不同字符及其计数。