LeetCode 热题 HOT 100(滑动窗口)3. 无重复字符的最长子串

45 阅读2分钟

题目描述

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

中等

提示

给定一个字符串 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 由英文字母、数字、符号和空格组成

解题思路

使用滑动窗口遍历所有不重复字符的子串,从而得到最长无重复的子串。

规则1:为了性能考虑使用大小为126的数组记录字符出现的最后位置。

规则2:在遍历一个新字符时,如果这个字符已经出现过就将start更新为这个字符最后出现的位置+1(左窗口滑动),如果这个字符从未出现则向右继续滑动窗口。

代码(哈希表(整型数组))

存储字符出现的最后位置

func lengthOfLongestSubstring(s string) int {
    charPosition := make([]int, 128)
    for i := range charPosition {
        charPosition[i] = -1
    }

    start := 0
    maxLength := 0

    for i := 0; i < len(s); i++ {
        ch := s[i]
        if lastPos := charPosition[ch]; lastPos >= start {
            start = lastPos + 1
        }
        currentLength := i - start + 1 
        maxLength = max(maxLength, currentLength)
        charPosition[ch] = i
    }

    return maxLength
}

存储字符出现次数

func lengthOfLongestSubstring(s string) int {
    charCounts := make([]int, 128)

    start := 0
    maxLength := 0

    for i := 0; i < len(s); i++ {
        charCounts[s[i]]++
        for charCounts[s[i]] > 1 {
            charCounts[s[start]]--
            start++
        }
        currentLength := i - start + 1
        maxLength = max(maxLength, currentLength)
    }

    return maxLength
}

代码(使用map记录每个字符最后出现的位置)

func lengthOfLongestSubstring(s string) int {
    // 使用map记录每个字符最后出现的位置
    charPosistion := make(map[rune]int)
    start := 0
    maxLength := 0

    // 使用for-range遍历字符串中的所有rune字符
    for i, char := range s {
        // 如何字符已经在当前窗口中出现过,更新start指针
        if lastPos, exists := charPosistion[char]; exists && lastPos >= start {
            start = lastPos+1
        }

        // 更新最大长度
        currentLength := i - start + 1
        if currentLength > maxLength {
            maxLength = currentLength
        }

        // 记录字符位置
        charPosistion[char] = i
    }

    return maxLength
}

// 1. 使用rune类型作为map键,可以处理任何Unicode字符
// 2. 记录同一个字符串上一次出现的最后位置,避免多次移动start指针
// 3. sMap命令不够直观,使用更具有描述性的 charPositions

代码(使用布尔数组记录窗口内出现的元素)

func lengthOfLongestSubstring(s string) int {
    charOccurence := make([]bool, 128)

    start, maxLength := 0, 0

    for i := 0; i < len(s); i++ {
        for charOccurence[s[i]] {
            charOccurence[s[start]] = false
            start++
        }
        charOccurence[s[i]] = true
        maxLength = max(maxLength, i-start+1)
    }

    return maxLength
}