无重复字符的最长子串
Category | Difficulty | Likes | Dislikes |
---|---|---|---|
algorithms | Medium (30.73%) | 2250 | - |
Tags
Companies
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
1窗口
这里使用两个指针
用两个指针表示一个范围
指针不断在移动
范围就会在变化
我们称这个过程为移动窗口
说到无重复,我们就会立马使用Set
我们窗口的范围就是
[right,left]
我们把窗口的元素都添加到Set
里面
如果在移动left
的过程,即添加新的元素时
发现该元素在Set
中出现
我们就要让移动right
到该元素后
这样就使得窗口内的元素不会重复
/*
* @lc app=leetcode.cn id=3 lang=javascript
*
* [3] 无重复字符的最长子串
*/
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
let [max, left, right] = [0, 0, 0]
const set = new Set()
while (right < s.length) {
if (!set.has(s[right])) {
set.add(s[right++])
max = Math.max(max, right - left)
} else {
set.delete(s[left++])
}
}
return max
};
2窗口优化
这里我们的left
是一步一步移动
直到删除了重复元素
即遇到了s[left] === s[right] 注:left !== right
此时删除了set.delete(s[left++])
那么现在set
里的元素范围就是[left,right]
因为set.has(s[right])
此时就不存在了,即false
所以就会走 if(!set.has(s[right]))
上面这里的left
是一步一步才走到
s[left] === s[right]
的位置的
那么
如果遇到重复的了
我们取出重复元素的下标直接赋给left
即可
而不是上面的left
一步一步的移动
直到s[left] === s[right]
然后把从(left,right]
开始
我们这里需要找到是
s[left] === s[right]
left
那么我们如果使用map
存储的是
<index,value>
我们在[left,right)
以后的时候
当s[right]
在该范围内发现有重复的
我们假装这个值是s[right_2]
我们只要使得left = right_2 + 1
使得那范围[right_2 + 1,right]
<值,下标>
var lengthOfLongestSubstring = function (s) {
let [max, left, right] = [0, 0, 0]
let map = new Map()
while (right < s.length) {
if (map.has(s[right]))
left = Math.max(map.get(s[right]) + 1, left)
map.set(s[right], right++)
max = Math.max(max, right - left)
}
return max
};