- 基础问题
最长无重复字符子串
- 2025-8-28 21:52:42 @
题意概括
给定一个字符串 s
,找到该字符串中不包含重复字符的 最长子串 的长度。子串是字符串中连续的一部分。
数据范围:
- 字符串
s
的长度满足 。 s
由英文字母、数字、符号和空格组成。
基础知识
滑动窗口 (Sliding Window)
这个问题是使用“滑动窗口”算法的经典范例。滑动窗口可以看作是一个由两个指针(左指针 l
和右指针 r
)界定的动态区间。这个窗口在字符串上滑动,根据特定条件进行扩展或收缩,以寻找满足条件的解。
-
窗口定义: 我们定义一个窗口
[l, r]
,表示当前正在考察的子串。我们的目标是维护这个窗口内的所有字符都是唯一的。 -
算法流程:
- 初始化左指针
l = 0
,右指针r = 0
,最大长度ans = 0
。 - 使用一个哈希表或数组(例如
cnt[128]
,对应 ASCII 码)来记录窗口内每个字符出现的次数。 - 不断向右移动右指针
r
来扩展窗口:- 将新字符
s[r]
加入窗口,并将其在cnt
数组中对应的计数加一。 - 检查
s[r]
在窗口内的计数是否大于 1。 - 如果大于 1,说明窗口内出现了重复字符。此时,我们需要收缩窗口。
- 不断向右移动左指针
l
,并将离开窗口的字符s[l]
的计数减一,直到s[r]
的计数变回 1 为止。这表示窗口内的重复字符已被移除。
- 将新字符
- 在每次扩展窗口(并可能伴随收缩)之后,窗口
[l, r]
内的子串都是不含重复字符的。我们用当前窗口的长度r - l + 1
来更新最大长度ans
。 - 重复此过程,直到右指针
r
到达字符串的末尾。
- 初始化左指针
复杂度分析:
- 时间复杂度: ,其中 是字符串的长度。虽然有两层循环,但每个字符最多被左指针和右指针各访问一次,所以总操作数是线性的。
- 空间复杂度: ,其中 是字符集的大小(对于 ASCII 是 128)。这是一个常数空间,所以空间复杂度为 。
样例
样例 1
- 输入:
abcabcbb
- 输出:
3
- 说明: 最长无重复字符子串是 "abc"。
样例 2
- 输入:
bbbbb
- 输出:
1
- 说明: 最长无重复字符子串是 "b"。
样例 3
- 输入:
pwwkew
- 输出:
3
- 说明: 最长无重复字符子串是 "wke"。
C++ 代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
string s;
cin >> s;
if (s.empty()) {
cout << 0 << endl;
return 0;
}
int n = s.length();
int cnt[128] = {0}; // 假设为 ASCII 字符集
int ans = 0;
int l = 0; // 滑动窗口左边界
for (int r = 0; r < n; r++) {
// 右指针 r 扩展窗口,新字符 s[r] 进入窗口
cnt[s[r]]++;
// 如果 s[r] 出现次数大于 1,说明窗口内有重复
// 需要收缩左边界 l,直到 s[r] 的次数变回 1
while (cnt[s[r]] > 1) {
cnt[s[l]]--;
l++;
}
// 此时 [l, r] 窗口内没有重复字符
// 更新最大长度
ans = max(ans, r - l + 1);
}
cout << ans << endl;
return 0;
}
0 条评论
目前还没有评论...