剑指 Offer 48. 最长不含重复字符的子字符串
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
1
2
3
| 输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
|
示例 2:
1
2
3
| 输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
|
示例 3:
1
2
3
4
| 输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
|
DP
哈希表
可以用一张哈希表来存放每个出现过的字母的最后位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| func lengthOfLongestSubstring(s string) int {
if len(s) == 0 {
return 0
}
hash := make(map[byte]int) // 记录每个字母最大的索引
dp := make([]int, len(s))
dp[0] = 1
hash[s[0]] = 0
maxResult := 1
for i := 1; i < len(s); i++ {
index, ok := hash[s[i]]
if !ok {
// s[i]未出现过
dp[i] = dp[i-1] + 1
} else {
if i-index > dp[i-1] {
// 上一个与s[i]相等的字母下标在dp[i-1]之前 可以加1
dp[i] = dp[i-1] + 1
} else {
// 上一个与s[i]相等的字母下标在dp[i-1]之中 没有办法
dp[i] = i - index
}
}
hash[s[i]] = i
if maxResult < dp[i] {
maxResult = dp[i]
}
}
return maxResult
}
|
dp 表还可以省略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| func lengthOfLongestSubstring(s string) int {
if len(s) == 0 {
return 0
}
hash := make(map[byte]int) // 记录每个字母最大的索引
hash[s[0]] = 0
maxResult := 1
pre := 1 // 记录dp[i-1]
var curResult int // 记录dp[i]
for i := 1; i < len(s); i++ {
index, ok := hash[s[i]]
if !ok {
// s[i]未出现过
curResult = pre + 1
} else {
if i-index > pre {
// 上一个与s[i]相等的字母下标在dp[i-1]之前 可以加1
curResult = pre + 1
} else {
// 上一个与s[i]相等的字母下标在dp[i-1]之中 没有办法
curResult = i - index
}
}
hash[s[i]] = i // 更新
pre = curResult
if maxResult < curResult {
maxResult = curResult
}
}
return maxResult
}
|
线性遍历
左边界 i 获取方式: 遍历到 s[j] 时,初始化索引 i = j - 1,向左遍历搜索第一个满足 s[i] = s[j] 的字符即可 。
不想写代码了
双指针
滑动窗口
其实原理是一样的,用一个 i 来框定左边界,保证 i+1 到 j 的字串无重复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // 双指针
func lengthOfLongestSubstring(s string) int {
if len(s) == 0 {
return 0
}
hash := make(map[byte]int) // 记录每个字母最大的索引
maxResult := 1
i := -1 // 左指针 定义左边界 保证i+1到j的字串无重复
for j := 0; j < len(s); j++ {
lastIndex, ok := hash[s[j]]
if ok && lastIndex > i {
// 上一个与s[j]相等的字母下标在左边界i右边 以其为新左边界
i = lastIndex
}
hash[s[j]] = j // 更新
if maxResult < j-i {
maxResult = j - i
}
}
return maxResult
}
|