1.题目以及测试用例:
题目说明:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2: 输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3: 输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。*
2.解题思路:
解析:
本题使用滑动窗口的思想可以进行解决
首先,定义三个变量:left表示当前滑动窗口的左边界,初值为0;maxLen表示最长不重复子串的长度,初值为0;map是一个Map对象,用来记录字符和字符对应的下标。
然后,通过一个循环遍历字符串s中的每个字符。在每次循环中,首先判断当前字符s[i]是否在map中存在,并且它的下标大于等于left。如果满足条件,则将left移动到s[i]上次出现的下标的下一个位置,确保滑动窗口中不包含重复的字符。
接下来,更新map中s[i]的值为当前下标i,表示最近一次出现s[i]的位置。然后,计算当前滑动窗口的长度i - left + 1,并与maxLen比较,取较大值作为新的maxLen。
最后,循环结束后,返回maxLen作为结果,即最长不重复子串的长度。
3.代码实现:
代码:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let left = 0;
let maxLen = 0;
let map = new Map();
for (let i = 0; i < s.length; i++) {
if (map.has(s[i]) && map.get(s[i]) >= left) {
left = map.get(s[i]) + 1;
}
map.set(s[i], i);
maxLen = Math.max(maxLen, i - left + 1);
}
return maxLen;
};
4.复杂度说明:
时间复杂度和空间复杂度解析:
时间复杂度是O(n),其中n是输入字符串的长度。这是因为代码中使用了一个循环来遍历字符串中的每个字符。
在循环中,大部分操作的时间复杂度都是O(1),例如对map的操作、取最大值、更新maxLen等。这些操作的时间复杂度不随输入规模增大而改变。
因此,循环的时间复杂度主要取决于字符串的长度n。每个字符都会被遍历一次,所以循环的时间复杂度是O(n)。
同时,代码中使用了一个map来记录字符和字符对应的下标,所以空间复杂度是O(k),其中k是字符串中不重复字符的个数。在最坏的情况下,字符串中的每个字符都不相同,因此k最多为n。所以空间复杂度可以近似看作是O(n)。