题解:最长不重复子串
题目传送门
一、题目重述
给定一个字符串 s,请找出其中不含有重复字符的最长子串的长度。
示例1:
输入:“abcabcbb”
输出:3
解释:最长无重复字符子串是"abc",长度为3
示例2:
输入:“abcdeff”
输出:6
解释:最长无重复字符子串是"abcdef",长度为6
二、题目分析
本题需要在一个字符串中找到最长的连续子串,该子串中所有字符都不重复。关键在于如何高效地判断和处理重复字符。
三、解题思路
使用**滑动窗口(双指针)**算法:
- 维护一个窗口(由左右指针l和r界定)
- 使用哈希集合存储当前窗口中的字符
- 当遇到重复字符时,移动左指针直到消除重复
- 始终保持窗口内无重复字符,并记录最大窗口大小
四、算法讲解
算法原理
滑动窗口算法适用于解决数组/字符串的子区间问题。通过动态调整窗口的左右边界,可以在O(n)时间内解决问题。
使用场景
- 需要寻找满足条件的连续子区间
- 通常用于字符串或数组问题
- 特别适合"最长无重复"这类问题
实现步骤
- 初始化左指针l=0和结果ans=0
- 右指针r从0开始遍历字符串
- 如果当前字符s[r]在集合中:
- 从集合中移除s[l]
- 左指针l右移
- 将s[r]加入集合
- 更新最大长度ans
示例解析
以**“abcabcbb”**为例:
- 初始:l=0, ans=0
- r=0(‘a’): 加入集合,ans=1
- r=1(‘b’): 加入集合,ans=2
- r=2(‘c’): 加入集合,ans=3
- r=3(‘a’): 重复,移除s0,l=1
- r=4(‘b’): 重复,移除s1,l=2
- …
- 最终ans=3
五、代码实现
#include <bits/stdc++.h>
using namespace std;
string s;
int main()
{
cin >> s;
unordered_set<char> st; // 用于存储当前窗口中的字符
int l = 0, ans = 0; // l是左指针,ans记录最大长度
for (int r = 0; r < s.size(); r ++) // r是右指针,遍历字符串
{
// 当发现重复字符时,移动左指针直到消除重复
while (st.find(s[r]) != st.end())
{
st.erase(s[l]); // 从集合中移除左指针字符
l ++; // 左指针右移
}
st.insert(s[r]); // 将当前字符加入集合
ans = max(ans, r - l + 1); // 更新最大长度
}
cout << ans <<"\n";
return 0;
}
六、代码重点细节解释
- unordered_set st:哈希集合,用于O(1)时间判断字符是否存在
- 双指针l和r:维护滑动窗口的边界
- while循环:处理重复字符的关键,确保窗口内无重复
- ans更新:每次扩展右边界后计算当前窗口长度
七、复杂度分析
- 时间复杂度:O(n),每个字符最多被访问两次(左右指针各一次)
- 空间复杂度:O(min(m,n)),m是字符集大小,最坏情况存储所有不同字符
八、关键点
- 滑动窗口的动态调整
- 哈希集合的快速查找
- 重复字符的处理方式
- 窗口长度的实时计算
九、总结
本题通过滑动窗口算法高效解决了最长无重复子串问题。关键在于:
- 使用哈希集合快速判断重复
- 动态调整窗口边界
- 实时更新最大长度
该算法思路清晰,实现简洁,是处理类似子串问题的经典方法。