「leetcode」3.无重复字符的最长子串

2,799 阅读2分钟

原题

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

思路

本题同样是一道使用双指针思路(滑动窗口)的题目。

我们的startend指针初始都是指向字符串的首部,紧接着end向后移动,每向后移动一步,都需要确认startend之间的字符串是否有重复的字符。

使用什么方法确认,是否有重复的字符呢?如果直接使用字符串的api, 比如indexOf,每一次查询的时间复杂度是O(n)。我们可以使用hash,优化查询的过程,每一次使用hash查询的时间复杂度是O(1)。

当遇到重复的字符时,说明以当前start对应的字符,开头的最长的无重复字符的子串已经确定了。以start字符开头的字符已经不会有更长的无重复子串了。

我们需要将start的指针向前移动一步。然后重复上述的过程,直到end指针指向字符串的尾部结束。(已经指向尾部了,也不会有更长的子串了)

1.png

  1. end向前递增

    2.png

  2. end向前递增

    3.png

  3. 发现重复的字符。以开头a的为首的最长无重复字符子串,已经确定。我们可以将start指针向前诺一位

    4.png

  4. end向前递增

    4.5.png

  5. end向前递增

    5.png

  6. ……重复上述的过程,直到end指向字符串的尾部,迭代结束。

代码


/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    
    const len = s.length
    const hashMap = new Map()
    
    let start = 0
    let end = 0
    let max = 0
    
    while (end < len) {
        if (!hashMap.has(s[end])) {
            hashMap.set(s[end], end)
            max = Math.max(max, hashMap.size)
            end += 1
        } else {
            while (start <= hashMap.get(s[end])) {
                hashMap.delete(s[start])
                start += 1
            }
            hashMap.set(s[end], end)
            end += 1
        }
    }
    
    return max
};