这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
背景
学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。
问题
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例1
输入: "abcabcbb"\
输出: 3 \
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2
输入: "bbbbb"\
输出: 1\
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3
输入: "pwwkew"\
输出: 3\
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。\
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解析
解法一: 使用数组来维护滑动窗口
先讲一下什么是滑动窗口: 窗口在我们我们代码中其实就是队列,那滑动代表的其实就是,这个删除队列左或者右两边的元素,这样看起来就是窗口左移或者右移。
再来看看我们这道题:
由于我们要取不含重复字符的最长字符串,所以我们要想到字符串中可能有很多不含重复字符的子字符串,我们要对比这些子串的长度。
-
这里我们先定义一个max=0,这里来记录当前最大子串的长度。
-
我们遍历字符串,判断当前字符是否在滑动窗口数组里
- 不在则
push进数组 - 在则删除滑动窗口数组里相同字符及相同字符前的字符,然后将当前字符
push进数组 - 根据当前窗口的长度和记录的max 取最大值
- 然后将
max更新为当前最长子串的长度
遍历完,返回 max 即可。
我们用一张图来看一下:
代码实现:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
//滑动窗口,也叫队列
let arr = [];
let max = 0;
let len=s.length;
for(let i = 0; i <len; i++) {
let index = arr.indexOf(s[i])
if(index !== -1) {
//移动窗口,删除左边的元素
arr.splice(0, index+1);
}
//存放当前字符
arr.push(s.charAt(i))
// 更新最大字符长度
max = Math.max(arr.length, max)
}
return max
};
验证结果:
那我们扩展下题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 。
这里我们需要找出最长的字符串,而不是最长字符串的长度。
- 我们需要了解知道最长字符串,我们上面题目已经可以获取到最长字符串的长度。
- 我们只需要记住最长字符串开始的角标即可。
- 默认我们设置为0,
- 当窗口滑动的时候,我们根据当前的max是否比原来的字符串长度大,来判断是否需要替换开始index。
- 清空滑动窗口,比较max
我们来看代码:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
//滑动窗口,也叫队列
let arr = [];
let max = 0;
let len=s.length;
//记录最大字符串
let start=0;
for(let i = 0; i <len; i++) {
let index = arr.indexOf(s[i])
//字符串中有重复的
if(index !== -1) {
//判断当前的子串是否比上次获取的子串长度更大
if(arr.length>max){
//获取当前不重复子串的长度
max=arr.length;
//计算当前不重复子串的开始索引
start=i-max;
}
//移动窗口,删除左边的元素
arr.splice(0, index+1);
}
//存放当前字符
arr.push(s.charAt(i))
}
//清空最后一次的窗口
if(arr.length>max){
max=arr.length;
start=s.length-max;
}
return s.substr(start,max)
};
验证结果:
结语
一步一步慢慢来,踏踏实实把活干!