题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例
示例1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例4:
输入: s = ""
输出: 0
解题思路
其实看到这个题我第一个想到的就是滑动窗口,滑动窗口是个怎么样的概念呢?顾名思义哈,就是一个会滑动的窗口,还能伸缩,厉不厉害。
那么怎么实现呢?我们可以想象一下,将字符串放在一个长方形的窗口里面,在这个窗口下面有一个能够伸缩和移动的滑动条(也就是滑动窗口),滑动条长度初始化为0。
-
- 首先自然是要先遍历,题目要求是无重复子串,那么我们就在遍历的过程中判断是否之前已经存在该字符;
-
- 那么我们怎么知道之前是否已经存在该字符呢?这里我们可以用 Set 来达到一个去重的效果。如果该字符不存在,就将该字符存进去;如果已经存在,就返回Set实例中当前成员的总数;
-
- 不存在的时候,滑动条长度就+1,即往右伸长 1 位;滑动条一旦碰到已经存在的字符,就停止扩展,那么当前滑动条的长度也就是 Set 实例中当前成员的总数;(下面说的滑动条统一为Set 实例)
-
- 那么问题又来了,我们怎么比较每次循环的时候的返回的 滑动条的长度呢?这里我们就可以来个第三者 ans, 初始值为 0,每遍历一次,都比较ans 和 滑动条的长度,谁大就赋值给 ans;
-
- 这是问题又来了,怎么让滑动条动起来呢?上面我们只涉及到了滑动条右边界的伸长,那缩短是怎么回事呢?诶,重点来了,我们只需要在除第一次遍历之后的每一次遍历都将滑动条的头部删除一个,可以理解为推动滑动条前进,这时再从步骤 2 开始往下执行
-
- 最后返回的 ans 即为该题解
AC代码
var lengthOfLongestSubstring = function(s) {
let arr = new Set()
let len = s.length;
let right = 0 // 滑动条的右边界,或者叫右指针
let ans = 0
for(let i = 0; i < len; i++) { // 滑动条的左边界,也可以理解为左指针
if(i != 0) {
arr.delete(s.charAt(i - 1))
}
while(right < len && !arr.has(s.charAt(right))) { // 满足条件,滑动条向右伸长 1
arr.add(s.charAt(right))
right++
}
ans = Math.max(ans, arr.size) // 碰到已经存在的跳出循环,比较每次遍历的滑动条的长度
}
return ans
};
刷题记录
Leetcode152 三角关系解释环型链表||? | 刷题打卡
Leetcode15 史上最详细题解之三数之和 | 刷题打卡
Leetcode215 数组中第K个最大的元素 | 刷题打卡
总结
题解呢是我根据自己的理解,用一些比较通俗的话写出来的,比如上面说的窗口和滑动条,目的就是希望通过这样的一个不那么抽象的模型,能够更加容易理解,措辞也不是那么专业,请见谅哈,哈哈。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情