题目:给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度
- 示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 - 示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
解题思路1:效率稍微低一些
- 先了解函数 string.indexOf(substring, start) 用于判断 string中start位置之后,substring第一次出现的位置,如果没有找到则返回-1
- 先利用indexOf 来 判断字母是否是第一次出现在这个子串中,判断方法为:如果字母的index小于当前循环i,则代表这个字母在前面已经出现过了,因为第一次出现的位置比当前循环的位置小
- 如果字母前面有存在重复的字母,则将minIndex移动到 重复字母的后一位 ,重新计算新的子串的长度,例如 abacd 则遇到第二个a的时候,则minIndex从b开始 计算新的子串
- 如果是第一次出现,则在这个子串里面没有重复字母,可以直接计算长度,不重复长度为当前循环i - minIndex + 1,第0个字母的长度为1,而不是0,所以要加1
- 由于每次循环的时候都把最大的长度保存在len值,如果拿到当前的最大长度i - minIndex + 1是大于之前保存的len,则Math.max()替换掉,保留不重复字符串的最大长度
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
// minIndex: 字符串某字母的最小index
let minIndex = 0
// len: 不重复字符串的最大长度
let len = 0
for(let i = 0; i < s.length; i++) {
s.indexOf(s[i], minIndex) < i ?
minIndex = s.indexOf(s[i], minIndex) + 1 :
len = Math.max(len, i - minIndex + 1)
}
return len
};
解题思路2: 双指针维护滑动窗口 高效一些
-
整体思路就是左指针不动,右指针在没遇到重复字符时一直往右移动,如果遇到重复字符了就重新开始记录,即左指针移动到最近一个重复字符的右边,重新开始记录。
滑动窗口用来记录最长不出现重复字符的子串的区间
哈希表用来记录每个字符最后(最新)出现的索引
abba
right = 0,首先遇到 a,没重复,long 更新为 1,同时 map.set('a', 0);
right = 1,遇到 b,没重复,long 更新为 2,同时 map.set('b', 1);
right = 2,遇到 b,重复了,同时判定 b 上一次出现位置是 1,大于等于 left,所以对 left 进行更新,更新成 1
right = 3,遇到 a,重复了,同时判定 a 上一次出现位置是 0,此时注意,如果没有判断 0 是否大于
等于 left 这一步 会发生什么?
1.如果直接让 left 更新成 a 上一次出现位置 0 再加1的话,此时 left 变成1,但很明显看出 [left, right) 区间即 [1, 3) 内有重复的 b,不符合!
2.所以得加上 map.get(s[right]) >= left 这个判定条件,右指针目前所指向的当前重复字符的上一次出现位置在左指针右边,保证滑动窗口左边界在遇到重复字符时一直能及时更新到最新状态,而不是用之
前的旧状态,而导致[left, right) 区间出现重复
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let left = 0;
let long = 0;
const map = new Map(), len = s.length;
for(let right = 0; right < len; right++){
// 遇到重复字符时还要判定 该重复字符的上一次出现位置是否在 滑动窗口左边界 left 的右边
if(map.has(s[right]) && map.get(s[right]) >= left){
left = map.get(s[right]) + 1; // 都满足,则更新,更新到最近出现的那个重复字符,它的上一个索引的右边
}
long = Math.max(long, right - left + 1); // 比较滑动窗口大小与 long 的长度
map.set(s[right], right); // 无论有没有重复,每次遍历都要更新字符的出现位置
}
return long;
};
作者:smooth-b
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/jian-dan-shuang-zhi-zhen-wei-hu-hua-dong-atl5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。