力扣热题100——滑动窗口
无重复字符的最长子串
- 步骤 1:初始状态
字符串 s = “abcabcbb”,哈希表 charSet 初始为空,双指针 left = 0,right = 0。
哈希表(charSet): {}
字符串: a b c a b c b b
指针: ↑ left/right
-
步骤 2:right = 0(字符 ‘a’)
操作:charSet.insert(‘a’)
哈希表存储:{‘a’}(字符 ‘a’ 作为键存入)
哈希表(charSet): {a}
字符串: a b c a b c b b
指针: ↑ ↑ left right
-
步骤 3:right = 1(字符 ‘b’)
操作:charSet.insert(‘b’)
哈希表存储:{‘a’, ‘b’}(新增字符 ‘b’)
哈希表(charSet): {a, b}
字符串: a b c a b c b b
指针: ↑ ↑ left right
-
步骤 4:right = 2(字符 ‘c’)
操作:charSet.insert(‘c’)
哈希表存储:{‘a’, ‘b’, ‘c’}(新增字符 ‘c’)
哈希表(charSet): {a, b, c}
字符串: a b c a b c b b
指针: ↑ ↑ left right
-
步骤 5:right = 3(字符 ‘a’)
检查:charSet.count(‘a’) → true(‘a’ 已存在)
操作:移除 left 指向的字符 ‘a’ → charSet.erase(‘a’),哈希表变为 {‘b’, ‘c’}
left++(left = 1)重新插入 ‘a’ → charSet.insert(‘a’),哈希表变为 {‘b’, ‘c’, ‘a’}
哈希表(charSet): {b, c, a}
字符串: a b c a b c b b
指针: ↑ ↑ left right
-
步骤 6:right = 4(字符 ‘b’)
检查:charSet.count(‘b’) → true(‘b’ 已存在)
操作:移除 left 指向的字符 ‘b’ → charSet.erase(‘b’),哈希表变为 {‘c’, ‘a’}
left++(left = 2)重新插入 ‘b’ → charSet.insert(‘b’),哈希表变为 {‘c’, ‘a’, ‘b’}
哈希表(charSet): {c, a, b}
字符串: a b c a b c b b
指针: ↑ ↑ left right
#include <string> // 引入string头文件,用于处理字符串
#include <unordered_set> // 引入unordered_set头文件,用于快速判断字符是否重复
using namespace std; // 使用std命名空间,简化代码书写class Solution { // 定义Solution类,封装解题方法
public: // 公共成员函数,外部可直接调用// 函数定义:接收字符串s,返回最长无重复字符子串的长度int lengthOfLongestSubstring(string s) {unordered_set<char> charSet; // 哈希集合,存储当前窗口内的所有字符(用于去重判断)int maxLen = 0; // 记录最长无重复子串的长度,初始为0int left = 0; // 滑动窗口的左边界指针,初始为0// 右指针right遍历字符串,作为窗口的右边界for (int right = 0; right < s.size(); ++right) {// 若当前字符s[right]已在窗口中(重复),则移动左指针缩小窗口// 直到窗口中不再包含s[right]while (charSet.count(s[right])) {charSet.erase(s[left]); // 移除左指针指向的字符left++; // 左指针右移,缩小窗口}// 将当前字符加入窗口(此时窗口中无重复字符)charSet.insert(s[right]);// 更新最长长度:取当前窗口长度(right - left + 1)和历史最大值的较大值maxLen = max(maxLen, right - left + 1);}// 返回最长无重复子串的长度return maxLen;}
};
找到字符串中所有字母异位词
#include <vector> // 引入vector容器头文件,用于存储结果和字符计数
#include <string> // 引入string头文件,处理字符串参数
using namespace std; // 使用std命名空间,简化代码书写class Solution { // 定义Solution类,封装解题方法
public: // 公共成员函数,外部可直接调用// 函数定义:接收两个字符串s和p,返回s中所有p的字母异位词的起始索引vector<int> findAnagrams(string s, string p) {vector<int> res; // 定义结果容器,存储符合条件的起始索引int sLen = s.size(), pLen = p.size(); // 计算s和p的长度// 边界判断:若s的长度小于p,不可能存在异位词,直接返回空结果if (sLen < pLen) return res;// 定义两个计数数组(26个元素对应a-z),统计字符出现次数vector<int> sCount(26, 0), pCount(26, 0);// 初始化计数:统计p的所有字符,以及s中前pLen个字符的出现次数for (int i = 0; i < pLen; ++i) {pCount[p[i] - 'a']++; // p[i]-'a'将字符转为0-25的索引(如'a'→0,'b'→1)sCount[s[i] - 'a']++; // 同步统计s的初始窗口(0到pLen-1)}// 若初始窗口的字符计数与p相同,说明0是有效的起始索引if (sCount == pCount) res.push_back(0);// 滑动窗口:从pLen位置开始遍历s的剩余字符for (int i = pLen; i < sLen; ++i) {// 移除窗口左侧的字符(i-pLen是即将滑出窗口的索引)sCount[s[i - pLen] - 'a']--;// 加入窗口右侧的新字符(当前i位置的字符)sCount[s[i] - 'a']++;// 若当前窗口的字符计数与p相同,记录起始索引(i-pLen+1)if (sCount == pCount) res.push_back(i - pLen + 1);}return res; // 返回所有有效起始索引}
};