没问题!我已经把原题内容、示例分析以及题目限制条件都补进去了。这样这份笔记就变成了一个完全闭环的刷题档案,以后复习看这一篇就全懂了!
📚 LeetCode 3090 算法与 C++ 基础学习笔记
📝 题目复盘
1. 题目描述
给你一个字符串s,请你找出满足每个字符最多出现两次的最长子字符串,并返回该子字符串的最大长度。
2. 示例剖析
示例 1:
输入:
s = "bcbbbcba"输出:
4解释:满足条件的最长子字符串是
"bcba"(长度为 4),在这个子串中,b出现了 2 次,c出现了 1 次,a出现了 1 次,没有任何字符超过 2 次。如果取"bcbbb"长度虽然是 5,但b出现了 4 次,不合法。示例 2:
输入:
s = "aaaa"输出:
2解释:满足条件的最长子字符串是
"aa"(长度为 2)。因为一旦到第三个a,数量就变成 3 溢出了。
3. 提示与数据范围
- 2≤s.length≤1002 \le \text{s.length} \le 1002≤s.length≤100(数据量很小,说明算法只要方向正确,绝对不会超时)。
s仅由小写英文字母组成(核心考点提示:意味着字符种类固定只有 26 个)。
🎯 核心算法:滑动窗口 (Sliding Window)
1. 适用场景
当题目要求在字符串或数组中寻找“最长/最短的连续子区间”,且区间满足某种“限制条件”时,首选滑动窗口。
2. 核心双指针逻辑
滑动窗口利用left(左指针)和right(右指针)来控制区间的边界:
- 窗口扩张:
right指针不断向右移动,将新元素纳入当前窗口,并更新状态(如计数器)。 - 窗口收缩:当新元素加入导致窗口违反限制条件时,保持
right不动,不断将left指针向右移动,并扣减状态,直到窗口重新合法。 - 结果更新:在窗口合法的任意时刻,当前窗口的长度为:
right - left + 1。
🛠️ C++ 核心语法与工具箱
1. 字符映射小技巧(哈希思想)
当题目限制字符仅为“小写英文字母”时,不需要使用复杂的哈希表,直接用大小为 26 的整型数组效率最高。
- 映射原理:利用 ASCII 码的连续性,将字符转换为
0-25的数组下标。 - 核心公式:
int b = s[right] - 'a'; - 如果
s[right]是'a',则'a' - 'a' = 0(对应数组第 0 个格子) - 如果
s[right]是'b',则'b' - 'a' = 1(对应数组第 1 个格子)
2. 数组的初始化方式(从新手到高手)
在 C++ 中,局部数组如果不手动初始化,里面会充满随机的垃圾数据。以下是三种完全等价的初始化方式:
- 高级简写版:
intcnt[26]{};// C++11 列表初始化,大括号留空代表全部填 0- 传统清晰版(推荐初学者使用,可读性好):
intcnt[26]={0};// 显式赋值,一眼就能看懂全部初始化为 0- 动态数组版(现代 C++ 标准写法):
vector<int>cnt(26,0);// 创建大小为 26 的 vector,默认值全为 0📦 什么是vector(动态数组)?
vector是 C++ 标准库(STL)中最常用的容器之一,它解决了传统数组“大小固定死、无法改变”的痛点。
1. 核心特点
- 智能变长:它像一个可以自动伸缩的抽屉,你可以随时往里面添加新数据(使用
push_back()),它会自动扩容。 - 安全方便:自带很多功能函数(如
.size()获取长度),比传统内存块更安全,不容易发生越界崩溃。 - 用法一致:虽然是动态的,但读取数据时依然支持和传统数组一样的方括号语法(如
cnt[i])。
2. 语法拆解
vector<int>cnt(26,0);// ▲ ▲ ▲ ▲ ▲// 容器名 类型 变量名 初始大小 初始默认值💻 本题最优解代码模板
结合上述笔记,最地道、可读性最好的 C++ 解法如下:
classSolution{public:intmaximumLengthSubstring(string s){intans=0;intleft=0;vector<int>cnt(26,0);// 使用 vector 初始化 26 个小写字母的计数器for(intright=0;right<s.length();++right){intb=s[right]-'a';// 将字符转化为 0-25 的索引cnt[b]++;// 窗口扩张:新字符计数加 1// 窗口收缩:如果当前字符超过 2 次,左边界右移,直到恢复合法while(cnt[b]>2){cnt[s[left]-'a']--;left++;}// 此时窗口必定合法,更新历史最长子串长度ans=max(ans,right-left+1);}returnans;}};- 时间复杂度:O(N)O(N)O(N),尽管内层有
while循环,但left和right指针各自最多都只把字符串从头到尾走了一遍,因此整体是线性的。 - 空间复杂度:O(1)O(1)O(1),只开辟了大小为 26 的固定辅助空间,与输入字符串
s的长度无关。