無重復字符的最長子串
- 步驟 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; // 返回所有有效起始索引}
};