滑动窗口–双指针、快慢指针的加难版
LeetCode 3 无重复字符的最长子串 2024.1.3
int lengthOfLongestSubstring(string s) {
//length记录最长子串长度
int length = 0;
//窗口的左侧索引
int left = 0;
//遍历
for(int i = 0; i < s.size(); i++)
{
//当遍历元素出现在窗口内时
if(find(s.begin()+left, s.end(), s[i])-s.begin() != i)
{
//更新最大窗口大小
length = length < i - left ? i-left : length;
//更新左侧窗口为遍历元素上一次出现位置的向右一个
left = find(s.begin()+left, s.end(), s[i])-s.begin() + 1;
continue;
}
}
//最后需要再更新一次最长子串长度
length = length < s.size() - left ? s.size()-left : length;
return length;
}
LeetCode 438 找到字符串中所有字母异位词 2024.1.6
vector<int> findAnagrams(string s, string p) {
//result数组存放答案索引
vector<int> result;
//用哈希表记录p字符串中元素及个数和窗口内元素及个数
unordered_map<char, int> need,window;
//统计p字符串中元素及个数
for(char c : p)
need[c]++;
//窗口边界,左闭右开
int left = 0, right = 0;
//sym变量记录窗口内达到p字符串中某种元素个数的元素种数
int sym = 0;
//当右边界未到数组右边界时遍历
while(right < s.size())
{
//记录当前right元素
char tempadd = s[right];
//右边界向右移动
right++;
//如果p字符串中有tempadd元素
if(need.count(tempadd))
{
//那么窗口内的tempadd元素个数增加
window[tempadd]++;
//当窗口内tempadd元素个数等于p字符串中需要tempadd元素个数时,sym++
if(window[tempadd] == need[tempadd])
sym++;
}
//当窗口大小大于等于p字符串长度时,需要减小窗口大小
while(right-left >= p.size())
{
//当窗口大小等于p字符串长度时,判断sym是否等于p字符串中元素种数
//当等于时,说明窗口中字符串是异位词的子串,将left加入到result中
if(sym == need.size())
result.push_back(left);
//记录窗口左侧元素,将要被删除的元素
char tempcut = s[left];
//左侧边界向右,left++
left++;
//如果删除的元素是p字符串中需要的,那么需要判断和操作
if(need.count(tempcut))
{
//判断如果窗口中该元素个数是否满足p字符串中需要
//如果需要,那么删除后,满足p字符串的元素种数减1
if(window[tempcut] == need[tempcut])
sym--;
//窗口中该元素个数减1
window[tempcut]--;
}
}
}
return result;
}
LeetCode 567 字符串的排列 2024.1.6
bool checkInclusion(string s1, string s2) {
//滑动窗口,基本与438题相同
//用哈希表记录s1字符串中元素及个数和窗口内元素及个数
unordered_map<char, int> need, window;
//sym变量记录窗口内达到s1字符串中某种元素个数的元素种数
int sym = 0;
//窗口边界,左闭右开
int left = 0, right = 0;
//统计p字符串中元素及个数
for(char c : s1)
need[c]++;
//当右边界未到数组右边界时遍历
while(right < s2.size())
{
//记录当前right元素
char tempadd = s2[right];
//右边界向右移动
right++;
//如果s1字符串中有tempadd元素
if(need.count(tempadd))
{
//那么窗口内的tempadd元素个数增加
window[tempadd]++;
//当窗口内tempadd元素个数等于s1字符串中需要tempadd元素个数时,sym++
if(window[tempadd] == need[tempadd])
sym++;
}
//当窗口大小大于等于p字符串长度时,需要减小窗口大小
if(right-left >= s1.size())
{
//记录窗口左侧元素,将要被删除的元素
char tempcut = s2[left];
//左侧边界向右,left++
left++;
//当窗口大小等于s1字符串长度时,判断sym是否等于s1字符串中元素种数
//当等于时,说明窗口中字符串是异位词的子串,直接返回true
if(sym == need.size())
return true;
//如果删除的元素是s1字符串中需要的,那么需要判断和操作
if(need.count(tempcut))
{
//判断如果窗口中该元素个数是否满足s1字符串中需要
//如果需要,那么删除后,满足s1字符串的元素种数减1
if(need[tempcut] == window[tempcut])
sym--;
//窗口中该元素个数减1
window[tempcut]--;
}
}
}
return false;
}
LeetCode 76 最小覆盖子串 2024.1.6
string minWindow(string s, string t) {
//滑动窗口
//用哈希表记录t字符串中元素及个数和窗口内元素及个数
unordered_map<char, int> need, window;
//窗口边界,左闭右开
int left = 0, right = 0;
//sym变量记录窗口内达到s1字符串中某种元素个数的元素种数
//start记录满足条件的最小子串的初始索引
//minlength记录最小子串的长度,默认为最大值
int start = 0, sym = 0, minlength = INT_MAX;
//统计t字符串中元素及个数
for(char c : t)
need[c]++;
//当右边界未到数组右边界时遍历
while(right < s.size())
{
//记录当前right元素
char tempadd = s[right];
//右边界向右移动
right++;
//如果t字符串中有tempadd元素
if(need.count(tempadd))
{
//那么窗口内的tempadd元素个数增加
window[tempadd]++;
//当窗口内tempadd元素个数等于t字符串中需要tempadd元素个数时,sym++
if(window[tempadd] == need[tempadd])
sym++;
}
//当窗口中元素种数>=t字符串中元素种类时
while(left < s.size() && sym >= need.size())
{
//如果当前满足条件的窗口的宽度小于记录的最小子串的长度,
//那么更新最小子串的开始索引和长度
//注意这里不要一直s.substr(pos, len),本题中内存爆了
if(right-left <= minlength)
{
start = left;
minlength = right-left;
}
//记录窗口左侧元素,将要被删除的元素
char tempcut = s[left];
//左侧边界向右,left++
left++;
//如果删除的元素是t字符串中需要的,那么需要判断和操作
if(need.count(tempcut))
{
//判断如果窗口中该元素个数是否满足s1字符串中需要
//如果需要,那么删除后,满足s1字符串的元素种数减1
if(need[tempcut] == window[tempcut])
sym--;
//窗口中该元素个数减1
window[tempcut]--;
}
}
}
//判断minlength是否为初始值,如果时则返回空字符串,否则返回最小子串
return minlength == INT_MAX ? "" : s.substr(start, minlength);
}
花式遍历数组
LeetCode 54 螺旋矩阵 2024.1.2
-
题意:第59题是将元素输入到nXn二维数组中,可以左闭右开,也可以左闭右闭;该题存在mXn大小矩阵,不一定能绕整圈,所以左闭右闭更好,不用考虑绕不了整圈的边界条件
vector<int> spiralOrder(vector<vector<int>>& matrix) {
//创建要返回的数组
vector<int> result;
//记录被遍历的二维数组的行数与列数
int m = matrix.size();
int n = matrix[0].size();
//记录遍历时上下左右边界
int up = 0, down = m-1, left = 0, right = n-1;
//当输出数组中元素个数不够时循环
while (result.size() < m*n)
{
// 因为要向右移动,所以保证上下边界内有元素
if(up <= down)
{
//遍历一整边,左闭右闭
for (int j = left; j <= right; j++)
{
result.push_back(matrix[up][j]);
}
//上边界下移
up++;
}
// 因为要向下移动,所以保证左右边界内有元素
if(left <= right)
{
for (int i = up; i <= down; i++)
{
result.push_back(matrix[i][right]);
}
//右边界左移
right--;
}
// 因为要向左移动,所以保证上下边界内有元素
if(up <= down)
{
for (int j = right; j >= left; j--)
{
result.push_back(matrix[down][j]);
}
//下边界上移
down--;
}
// 因为要向上移动,所以保证左右边界内有元素
if(left <= right)
{
for (int i = down; i >= up; i--)
{
result.push_back(matrix[i][left]);
}
//左边界右移
left++;
}
}
return result;
}