【leet-code清晰解题思路✅】3. 无重复字符的最长子串

73 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第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 由英文字母、数字、符号和空格组成

解题思路

  • 最直接的思路是两重for循环枚举所有子串,对每一个子串统计是否有重复的部分。时间复杂度来到了O(n^3)。超过了题目限制,就不再实现了。
  • 我们可以注意到子字符串的左边界总是在右边界左边,可以用两个指针去表示。可以左右边界从0开始,右边界一直向右走,统计现在左右边界之间是否有重复,如果有,可以将左指针向右走,直到没有重复的字母。重复刚才过程,并记录最大长度。这也叫滑动窗口,像一个可变长的窗口在滑动。由于左右指针只从左到右一次,时间复杂度为O(n)。
    • 这里数组记录对应字母出现的下标+1,如果遍历发现值>0 说明出现过
func lengthOfLongestSubstring(s string) int {
   a := [128]int{}
   l := 0
   maxLength := 0
   for r := 0; r < len(s); r++ {
      if a[s[r]] > l {
         l = a[s[r]]
      }
      a[s[r]] = r + 1
      if r-l+1 > maxLength {
         maxLength = r - l + 1
      }
   }
   return maxLength
}

image.png

  • 如果用map记录字母的次数,时间和数组差不多,但是空间会额外O(n)
func lengthOfLongestSubstring(s string) int {
   a := make(map[byte]int)
   l := 0
   maxLength := 0
   for r := 0; r < len(s); r++ {
      if idx, ok := a[s[r]]; ok && idx >= l {
         l = idx + 1
      }
      a[s[r]] = r
      if r-l+1 > maxLength {
         maxLength = r - l + 1
      }
   }
   return maxLength
}

image.png