问题定义
给定一个字符串,要求找出其中不含有重复字符的 最长子串 的长度。例如:
- 对于字符串
"abcabcbb"
,最长无重复子串是"abc"
,长度为 3 - 对于字符串
"bbbbb"
,最长无重复子串是"b"
,长度为 1 - 对于字符串
"pwwkew"
,最长无重复子串是"wke"
,长度为 3
算法实现
核心算法思路
本解法采用了滑动窗口 + 哈希表的高效策略,其主要特点包括:
- 使用
unordered_map
存储字符最后出现的索引 - 动态维护当前无重复子串的长度
- 实时更新最大无重复子串长度
代码解析
class Solution {
public:
int lengthOfLongestSubstring(string s) {
// 存储上一次出现的索引
unordered_map<char, int> char_index;
int max_length = 0; // 最大无重复子串长度
int cur_length = 0; // 当前无重复子串长度
for (int i = 0; i < s.length(); i++) {
// 检查当前字符是否在当前子串中重复
if (char_index.count(s[i]) && char_index[s[i]] + cur_length >= i) {
// 更新最大长度
max_length = max(max_length, cur_length);
// 重新计算当前子串长度
cur_length = i - char_index[s[i]];
}
else {
// 当前字符可以加入子串
cur_length++;
}
// 更新字符最后出现的索引
char_index[s[i]] = i;
}
// 关键:处理从头到尾无重复的情况
return max(max_length, cur_length);
}
};
关键技术点解析
1. 哈希表记录索引
- 使用
unordered_map<char, int>
快速定位字符上次出现的位置 - 时间复杂度 O(1) 的查找和插入操作
2. 滑动窗口策略
- 动态调整当前子串的起始和结束位置
- 根据重复字符实时更新窗口大小
3. 边界条件处理
- 最后一步
max(max_length, cur_length)
处理全局最长子串 - 避免遗漏从头到尾无重复的特殊情况
算法复杂度分析
- 时间复杂度:O(n),其中 n 为字符串长度
- 空间复杂度:O(k),k 为字符集大小(通常为常数)
算法优缺点比较
优点
- 空间效率高
- 实时更新最大子串长度
- 单次遍历完成计算
潜在改进
- 可以使用定长数组替代哈希表,进一步优化空间
- 对于 Unicode 字符集可能需要调整存储策略
总结
本算法通过巧妙的滑动窗口和哈希表技术,以 O(n) 的时间复杂度高效解决了无重复字符最长子串问题。关键在于实时更新和正确处理重复字符边界情况。
附加建议
对于面试或实际编码,建议:
- 手动模拟几个测试用例
- 注意处理空串和特殊输入
- 理解算法的状态转移逻辑