使用滑动窗口来解决这一题
使用map来存储当前进入窗口的元素
如果下一个进来的元素在map中存在,此时就需要更新滑动窗口的起始位置
如果下一个进来的元素不存在map之中,那就继续存入map之中
错误代码
var lengthOfLongestSubstring = function (s) {
let map = new Map()
let res = 0
let start = 0
for (let i = 0; i < s.length; ++i) {
if (map.has(s[i])) {
start = map.get(s[i]) + 1
}
map.set(s[i], i)
res = Math.max(res, i - start + 1)
}
return res
};
当测试用例为 'abba' 时
可以看到图片中的红框,此时当'a'再次进入if的时候,start = 0 + 1 = 1, i = 3
start变小了,会导致窗口变大,要防止这种情况的出现
此时会导致错误
所以当重复的字符再次出现的时候,要选择此时重复出现的字符的最大索引
正确代码
map
var lengthOfLongestSubstring = function (s) {
let map = new Map()
let res = 0
let start = 0
for (let i = 0; i < s.length; ++i) {
if (map.has(s[i])) {
start = Math.max(start, map.get(s[i]) + 1)
}
map.set(s[i], i)
res = Math.max(res, i - start + 1)
}
return res
};
set
在set.has(s[right])为真的时候,为什么要删除左边?
s = "abba"
- 初始:
left=0, right=0, set={} s[right]=a不在 set → 加入 → set={a}, right=1s[right]=b不在 set → 加入 → set={a,b}, right=2s[right]=b在 set- 不能删
s[right],因为它还没加进去 - 我们删
s[left]→ 删a,set={b}, left=1 - 还是重复,因为窗口
[1,1]里还有个b - 继续删
s[left]→ 删b,set={}, left=2 - 现在
s[right]=b可以加进来了 → set={b}, right=3
- 不能删
这样才能保证窗口始终没有重复。
删除 s[left] 是为了不断缩小窗口,直到能安全地接纳 s[right]
var lengthOfLongestSubstring = function (s) {
let left = 0,
right = 0;
let set = new Set();
let maxLen = 0;
while (right < s.length) {
if (set.has(s[right])) {
set.delete(s[left]);
left++;
} else {
set.add(s[right]);
right++;
maxLen = Math.max(maxLen, right - left);
}
}
return maxLen;
};