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

90 阅读2分钟

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

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

标签:思维、哈希、双指针、滑动窗口


思路1:双指针

  • 右指针不断向后遍历,通过哈希记录字母出现的位置,如果出现重复的字母,那么可以确定最长子串要在这两个字母区间中取。
  • 左边界要额外处理一下,对一开始没有出现过的字母要赋一个初始的位置-1,同时左指针从-1开始遍历。之后每次更新都要处理左边界
  • 边界问题:这个和滑动窗口不一样的是没有记录整个窗口内所有元素,所以需要进行边界判定。判断左指针和map的值

难点:这个题卡思路的地方是左指针和上一个出现的字母边界处理

代码:

// 记录最长子串上一个字符出现的位置,如果遇到重复字符,就从上一个字符的位置开始计算最长子串
func lengthOfLongestSubstring(s string) int {
    //if len(s) == 0 {
    // return 0
    //}

    lang := 0
    alphabet := make(map[uint8]int)
    // 从-1开始
    for i, j := -1, 0; j < len(s) && i <= j; j++ {
       v := s[j]
       if _, ok := alphabet[v]; !ok {
          alphabet[v] = -1
       }
       // 边界处理
       i = max(alphabet[v], i)
       lang = max(lang, j-i)

       alphabet[v] = j
    }
    return lang
}
func max(a, b int) int {
    if a < b {
       return b
    }
    return a
}

思路2:滑动窗口

和双指针其实是一个思路,只不过把处理边界问题隐藏在了窗口滑动过程中。

用左指针记录窗口的起始位置,右指针记录窗口的末位置。移动窗口的时候发现有重复元素,就移除左边界字母,直到无重复元素

func lengthOfLongestSubstring(s string) int {
    n := len(s)
    if n <= 1 {
       return n
    }
    lang := 0
    alphabet := [128]bool{} // 阿斯克码覆盖范围
    left, right := 0, 0
    for right < n {
       for alphabet[s[right]] {
          alphabet[s[left]] = false
          left++
       }
       alphabet[s[right]] = true
       lang = max(lang, right-left+1)
       right++
    }

    return lang
}

func max(a, b int) int {
    if a > b {
       return a
    }
    return b
}