题目描述:给定一个字符串 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
}