3. [✔][M]无重复字符的最长子串
给定一个字符串 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由英文字母、数字、符号和空格组成
题解:
双指针、快慢指针、hash map、滑动窗口。
滑动窗口问题,使用快慢指针,一前一后判断窗口扩大还是缩小。核心难点就在于窗口是扩大还是缩小的判断上。
/*
 * @lc app=leetcode.cn id=3 lang=typescript
 *
 * [3] 无重复字符的最长子串
 */
// @lc code=start
function lengthOfLongestSubstring(s: string): number {
    let win = new Map();//窗口字符计数器
    let left = 0;//左指针
    let right = 0;//右指针
    let len = 0;//最长子串
    while (right < s.length) {//没有到s末尾,一直执行循环
        let c = s[right];//最右边字符
        right++;//窗口扩大
        win.set(c, (win.get(c) || 0) + 1);//窗口中增加一个right位置字符
        while (win.get(c) > 1) {//窗口中已经有增加的字符了,继续循环,直到win中这个字符只有1次
            let d = s[left];//left位置字符
            left++;//窗口缩小
            win.set(d, (win.get(d) || 0) - 1);//减掉1次字符数量
        }
        len = Math.max(len, right - left);//结果在最大值和当前计算的字符长度之间取最大值
    }
    return len;
};
// @lc code=end