问题描述:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
总结一下这个题目的解题思路:
主要是滑动窗口这个概念,维护一个内部包含不重复元素的窗口,如果有新元素进来,检查一下这个元素是否在窗口内;如果不存在,就加入窗口,得到一个新的窗口。如果存在,就将窗口中相同元素及之前的元素剔除,加入新元素。形成一个不含重复元素的新窗口。然后,检测新窗口的长度,和最大长度比较取最大。
无论是数组,字符串还是map,其实都是维护了一个字串。不同的是维护数组和字符串下标的时间复杂度是O(n^2),而map是O(n)。下面可以帮助理解的图关于数组这个方法的。
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
// 维护数组的方法,实现滑动窗口
// arr存放的是最长的子数组
let arr=[],maxlen=0;
for(let i=0;i<s.length;i++){
//看arr数组中是否存在s[i]元素
let index=arr.indexOf(s[i]);
if(index!==-1){
//表示此元素和最长子数组中重复
//移除重复元素和之前的元素
arr.splice(0,index+1);
}
//把s中该元素放进arr数组
arr.push(s.charAt(i));
maxlen=Math.max(maxlen,arr.length);
}
return maxlen;
};
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
// 维护字符串下标的方式实现
let maxlen=0;
//left表示维护的字串的左侧下标,right为字串的右侧下标
for(let left=0,right=0;right<s.length;right++){
//index表示子串中是否含有新元素
let index=s.substring(left,right).indexOf(s[right]);
if(index!==-1){
//移动字串左侧下标,进行滑动
left=left+index+1;
}
maxlen=Math.max(maxlen,right-left+1);
}
return maxlen;
};
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
// 使用map实现,map中保存已经检查过的字符
let map=new Map(),maxlen=0;
for(let i=0,j=0;j<s.length;j++){
//此处检测的是map中是否有该元素,但是请注意,并不是代表滑动的字串中“一定”有该元素
if(map.has(s[j])){
//里面这个比较很重要,表示的是如果字串中有新元素,就将新元素的下标加一作为字串左侧下标
//如果字串中,没有这个元素。那就按照之前的左侧下标
//其实理解起来不难,但是按照之前两个方法的思路,容易搞混,希望仔细思考(我太笨了)
i=Math.max(map.get(s[j])+1,i);
}
maxlen=Math.max(maxlen,j-i+1);
map.set(s[j],j);
}
return maxlen;
};