字符串最长的不重复子串
使用滑动窗口算法找出字符串中最长的不含重复字符的子串
问题
给定一个字符串,找出其中最长的不含有重复字符的子串的长度。例如,字符串 “abcabcbb” 的最长不重复子串是 “abc”,长度为 3;字符串 “bbbbb” 的最长不重复子串是 “b”,长度为 1。
解答
/**
* 查找字符串中最长的不重复子串
* @param {string} str - 输入字符串
* @return {string} - 返回最长不重复子串
*/
function longestUniqueSubstring(str) {
if (!str || str.length === 0) {
return '';
}
let maxLength = 0; // 最长子串的长度
let maxStart = 0; // 最长子串的起始位置
let left = 0; // 滑动窗口左指针
const charMap = new Map(); // 存储字符及其最新位置
for (let right = 0; right < str.length; right++) {
const char = str[right];
// 如果字符已存在且在当前窗口内,移动左指针
if (charMap.has(char) && charMap.get(char) >= left) {
left = charMap.get(char) + 1;
}
// 更新字符的最新位置
charMap.set(char, right);
// 更新最长子串信息
const currentLength = right - left + 1;
if (currentLength > maxLength) {
maxLength = currentLength;
maxStart = left;
}
}
return str.substring(maxStart, maxStart + maxLength);
}
/**
* 只返回最长不重复子串的长度
* @param {string} str - 输入字符串
* @return {number} - 返回最长不重复子串的长度
*/
function longestUniqueSubstringLength(str) {
if (!str || str.length === 0) {
return 0;
}
let maxLength = 0;
let left = 0;
const charMap = new Map();
for (let right = 0; right < str.length; right++) {
const char = str[right];
if (charMap.has(char) && charMap.get(char) >= left) {
left = charMap.get(char) + 1;
}
charMap.set(char, right);
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}
使用示例
// 示例1:基本使用
console.log(longestUniqueSubstring('abcabcbb')); // 输出: "abc"
console.log(longestUniqueSubstringLength('abcabcbb')); // 输出: 3
// 示例2:全部重复字符
console.log(longestUniqueSubstring('bbbbb')); // 输出: "b"
console.log(longestUniqueSubstringLength('bbbbb')); // 输出: 1
// 示例3:全部不重复
console.log(longestUniqueSubstring('abcdef')); // 输出: "abcdef"
console.log(longestUniqueSubstringLength('abcdef')); // 输出: 6
// 示例4:包含空格和特殊字符
console.log(longestUniqueSubstring('pwwkew')); // 输出: "wke"
console.log(longestUniqueSubstringLength('pwwkew')); // 输出: 3
// 示例5:空字符串
console.log(longestUniqueSubstring('')); // 输出: ""
console.log(longestUniqueSubstringLength('')); // 输出: 0
// 示例6:中文字符
console.log(longestUniqueSubstring('我爱编程编程')); // 输出: "我爱编程"
console.log(longestUniqueSubstringLength('我爱编程编程')); // 输出: 4
关键点
-
滑动窗口算法:使用左右两个指针维护一个动态窗口,窗口内始终保持无重复字符
-
哈希表优化:使用 Map 存储每个字符最后出现的位置,实现 O(1) 时间复杂度的查找
-
左指针移动策略:当遇到重复字符时,将左指针移动到重复字符上次出现位置的下一位
-
边界条件判断:需要确保重复字符在当前窗口内(
charMap.get(char) >= left),避免左指针回退 -
时间复杂度:O(n),其中 n 是字符串长度,每个字符最多被访问两次
-
空间复杂度:O(min(m, n)),其中 m 是字符集大小,n 是字符串长度
目录