题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
一. 两层循环
外层依次遍历字符串的每个字符,内层使用set保存已出现字符,使用两个变量分别标记开始和结尾,如果内层的长度已经大于标记,则移动标记到当前位置,如果出现重复,则结束内层循环。
js实现
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
if (!s.length) {
return 0
}
var start = 0
var end = 1
for (var i=0;i<s.length;i++) {
var set = new Set()
set.add(s[i])
for (var j=i+1;j<s.length;j++) {
if (set.has(s[j])) {
break
}
if (j + 1 - i > end - start) {
start = i
end = j + 1
}
set.add(s[j])
}
}
return end - start
};
复杂度分析
时间复杂度:O(n2)
空间复杂度:O(n)
测试结果
✔ Accepted
✔ 987/987 cases passed (300 ms)
✔ Your runtime beats 23.95 % of javascript submissions
✔ Your memory usage beats 24.1 % of javascript submissions (41.8 MB)
二. 优化的两层循环
在两层循环的基础上,我们可以不使用两个变量标记开始和结尾,我们只需要标记长度即可,所以,只使用一个变量表示长度即可。
js实现
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
if (!s.length) {
return 0
}
var len = 1
for (var i=0;i<s.length;i++) {
var set = new Set()
set.add(s[i])
for (var j=i+1;j<s.length;j++) {
if (set.has(s[j])) {
break
}
set.add(s[j])
if (set.size > len) {
len = set.size
}
}
}
return len
};
复杂度分析
时间复杂度:O(n2)
空间复杂度:O(n)
测试结果
✔ Accepted
✔ 987/987 cases passed (276 ms)
✔ Your runtime beats 24.27 % of javascript submissions
✔ Your memory usage beats 22.38 % of javascript submissions (41.8 MB)
三. 滑动窗口
定义子字符串的左右边界,起始时均为0,检测右边界是否重复,如果没有重复,则右边界向右滑动,如果重复,则左边界向右滑动。
js实现
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
var len = s.length
var set = new Set()
var result=0, i=0, j=0
while (i < len && j < len) {
if (!set.has(s[j])) {
set.add(s[j])
j++
result = Math.max(result, j - i)
} else {
set.delete(s[i])
i++
}
}
return result
};
复杂度分析
时间复杂度:O(2n)
空间复杂度:O(n)
测试结果
✔ Accepted
✔ 987/987 cases passed (104 ms)
✔ Your runtime beats 93.28 % of javascript submissions
✔ Your memory usage beats 78.94 % of javascript submissions (38.7 MB)
四. 优化的滑动窗口
在滑动窗口的基础上,我们使用Map代替Set保存值对应的位置,遍历时,如果值在Map中存在且在左边界内,则表示值对应位置及它的的左侧无需再进行判断,这样我们最多只需遍历一次即可得出结果。
js实现
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
var len = s.length
var map = new Map()
var result=0, i=0, j=0
while (i < len && j < len) {
if (map.has(s[j])) {
i = Math.max(map.get(s[j]), i)
}
result = Math.max(result, j+1-i)
map.set(s[j], ++j)
}
return result
};
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)
测试结果
✔ Accepted
✔ 987/987 cases passed (92 ms)
✔ Your runtime beats 98.97 % of javascript submissions
✔ Your memory usage beats 82.05 % of javascript submissions (38.1 MB)