无重复字符的最长子串
https://leetcode.cn/problems/longest-substring-without-repeating-characters/
问题原题
给定一个字符串 s,请你找出其中不含有重复字符 的最长子串的长度。
-
示例 1:
输入:
s = "abcabcbb"输出:
3解释: 无重复字符的最长子串是
"abc",长度为 3。 -
示例 2:
输入:
s = "bbbbb"输出:
1解释: 无重复字符的最长子串是
"b",长度为 1。 -
示例 3:
输入:
s = "pwwkew"输出:
3解释: 无重复字符的最长子串是
"wke",长度为 3。
提示:
0 <= s.length <= 5 * 10^4s由英文字母、数字、符号和空格组成
基础解答:暴力枚举法
思路
- 枚举所有可能的子串,检查每个子串是否包含重复字符
- 记录无重复字符的子串的最大长度
- 优点:逻辑简单,容易理解;缺点:时间复杂度高(O(n3)O(n^3)O(n3)),仅适合短字符串
C++ 代码
cpp
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;
// 暴力解法:枚举所有子串
int lengthOfLongestSubstring(string s) {
int n = s.size();
int maxLen = 0;
// 枚举子串起始位置
for (int i = 0; i < n; ++i) {
// 用集合存储当前子串的字符,判断是否重复
unordered_set<char> charSet;
// 枚举子串结束位置
for (int j = i; j < n; ++j) {
// 字符重复,跳出当前循环
if (charSet.count(s[j])) {
break;
}
charSet.insert(s[j]);
// 更新最大长度
maxLen = max(maxLen, j - i + 1);
}
}
return maxLen;
}
// 测试
int main() {
string s1 = "abcabcbb";
string s2 = "bbbbb";
string s3 = "pwwkew";
cout << lengthOfLongestSubstring(s1) << endl; // 3
cout << lengthOfLongestSubstring(s2) << endl; // 1
cout << lengthOfLongestSubstring(s3) << endl; // 3
return 0;
}
进阶解答:滑动窗口(最优解)
思路
- 滑动窗口:用左右指针表示当前无重复字符的子串窗口
- 哈希表:记录每个字符最后出现的索引,快速判断重复
- 遇到重复字符时,直接将左指针跳转到重复字符的下一位,避免重复遍历
- 时间复杂度:O(n)O(n)O(n),空间复杂度:O(1)O(1)O(1)(字符集有限),完美适配题目数据范围
C++ 代码
cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 滑动窗口 + 哈希表(最优解法)
int lengthOfLongestSubstring(string s) {
// 存储字符最后出现的索引,ASCII码共128个字符,初始化为-1
vector<int> charIndex(128, -1);
int left = 0; // 窗口左指针
int maxLen = 0; // 最大长度
for (int right = 0; right < s.size(); ++right) {
char ch = s[right];
// 字符重复,更新左指针:取当前左指针 和 重复字符下一位 的最大值
if (charIndex[ch] != -1) {
left = max(left, charIndex[ch] + 1);
}
// 更新当前字符的最后出现位置
charIndex[ch] = right;
// 计算当前窗口长度,更新最大值
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
// 测试
int main() {
string s1 = "abcabcbb";
string s2 = "bbbbb";
string s3 = "pwwkew";
cout << lengthOfLongestSubstring(s1) << endl; // 3
cout << lengthOfLongestSubstring(s2) << endl; // 1
cout << lengthOfLongestSubstring(s3) << endl; // 3
return 0;
}
或者用滑动窗口 + unordered_map
cpp
#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;
int lengthOfLongestSubstring(string s) {
// 哈希表:key = 字符,value = 字符最后一次出现的索引
unordered_map<char, int> charMap;
int left = 0; // 窗口左边界
int maxLen = 0; // 记录最长长度
for (int right = 0; right < s.size(); ++right) {
char current = s[right];
// 如果当前字符已经在窗口内出现过 → 移动左指针
if (charMap.find(current) != charMap.end() && charMap[current] >= left) {
left = charMap[current] + 1;
}
// 更新当前字符的最新位置
charMap[current] = right;
// 计算窗口长度,更新最大值
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
// 测试主函数
int main() {
string s1 = "abcabcbb";
string s2 = "bbbbb";
string s3 = "pwwkew";
cout << lengthOfLongestSubstring(s1) << endl; // 3
cout << lengthOfLongestSubstring(s2) << endl; // 1
cout << lengthOfLongestSubstring(s3) << endl; // 3
return 0;
}