定长滑动窗口--灵神题单(一刷进阶)

简介: 这篇文章主要围绕灵神题单中的定长滑动窗口进阶题进行探讨,首先解决了一些基本题目,然后附带了一些相对困难题目的解题思路。值得注意的是,大部分解答都是在前人的基础上进行了一些小的修改和调整。希望文章对大家的学习和解题能力有所帮助。如果您需要更具体的内容或者对某一部分有兴趣深入讨论,请告诉我!


目录

第一题:2134. 最少交换次数来组合所有的 1 II - 力扣(LeetCode)

按照力扣的 滑动窗口 标签刷到这题,知道是滑窗,但想了半天没想到怎么滑。
再看了下灵神给的滑动窗口题单【题单】滑动窗口(定长/不定长/多指针) 里面把这题归类为定长滑动窗口。
说是定长滑窗。那只能是 1的总数 或 0的总数 当作固定的窗口长度吧。
那就两种情况都写一下,反正都是O(n)。
窗口长度固定为0的总数,那窗口内 要被替换成0的个数,即窗口内1的个数就是结果,求最小
窗口长度固定为1的总数,那窗口内 要被替换成1的个数,即窗口内0的个数就是结果,求最小
上述两个结果都求出来,然后再求个最小,然后就通过了。
定长滑窗的具体写法是 初始窗口处理好,然后右端进一个,左端出一个。
class Solution {
public:
int minSwaps(vector& nums) {
int n = nums.size();
int count_1 = 0;// 统计一的个数
for (auto& num : nums) count_1 += num;
int count_0 = n - count_1;
int ret = n;
for (int left = 0, right = 0, count = 0; right < n; right++)
{
// 进窗口
count += nums[right];
// 判断
if (right - left + 1 >= count_1)
{
ret = min(ret, count_1 - count);
count -= nums[left++];
}
}
for (int left = 0, right = 0, count = 0; right < n; right++)
{
// 进窗口
if (nums[right] == 0)
{
count += 1;
}
// 判断
if (right - left + 1 >= count_0)
{
ret = min(ret, count_0 - count);
if (nums[left++] == 0) count -= 1;
}
}
return ret;
}
};
第二题:567. 字符串的排列 - 力扣(LeetCode)

这一道题如果想到要去使用哈希表,其实是非常的简单的,最主要的是如何想办法去优化。

检查字符串s2是否包含s1的排列。你通过hash1记录s1中每个字符的频率,并通过hash2跟踪当前窗口内字符的频率。每次滑动窗口时,更新字符的计数并检查是否满足s1的字符频率。优化点在于:1. 通过滑动窗口避免重复遍历,

  1. 只对s1中出现的字符进行操作,减少不必要的计算。通过count变量追踪窗口中字符的匹配数量,避免了每次都重新计算。

class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n1 = s1.size();
int n2 = s2.size();
if (n1 > n2)
return false; // 如果s1的长度大于s2,直接返回false
unordered_map hash1;
for (auto& e : s1)
hash1[e]++;
unordered_map hash2;
for (int left = 0, right = 0, count = 0; right < n2; right++) {
// 进窗口
char in = s2[right];
if (hash1.find(in) != hash1.end()) {
hash2[in]++;
if (hash2[in] <= hash1[in])
count++;
}
// 判断 出
if (right - left + 1 >= n1)
{
if (count == n1)
{
return true;
}
char ou = s2[left++];
if (hash1.find(ou) != hash1.end())
{
// 如果移出的字符在 s1 中出现过,更新 hash2 和 count
if (hash2[ou] <= hash1[ou])
{
count--;
}
hash2[ou]--;
}
}
}
return false;
}
};
第三题:438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

这一道题其实也是非常简单的定长滑动窗口。没什么难度。就不解释了,直接给代码吧。

但是还是要给出疑问:

使用哈希表好?还是数组好? 给出为什么?

class Solution {
public:
vector findAnagrams(string s, string p) {
int hash1[26]={0};
int m=p.size();
for(auto& e:p) hash1[e-'a']++;
int hash2[26]={0};
int n=s.size();
vector ret;
for(int left=0,right=0,count=0;rightm )
{
if(hash2[ou-'a']--<=hash1[ou-'a']) count--;
left++;
}
//更新结果
if(count==m)
{
ret.push_back(left);
}
}
return ret;
}
};
第四题:2156. 查找给定哈希值的子串 - 力扣(LeetCode)

这一道题其实也是不是很难,虽然力扣给出是困难题,但是只要了解一些数学知识,把题目的过程简化,难度连中等题都谈不上。

但这一切前提都是你对该部分数学知识了解,如果不了解,根本无思路。

推荐文章:分享丨模运算的世界:当加减乘除遇上取模(模运算恒等式/费马小定理) - 力扣(LeetCode)

代码:

class Solution {
public:
string subStrHash(string s, int power, int modulo, int k, int hashValue) {
int n=s.size();
string ret;
int h = 0; // 子串哈希值
for(int left=0,right=0;right=k)
{
if(h==hashValue)
{
ret=s.substr(left,k);
}
// 出
if(h==0) h=modulo;
h=(long long)h-(s[left++]-'a'+1)* power % modulo;
}
}
return ret;
}
};
第五题:1016. 子串能表示从 1 到 N 数字的二进制串 - 力扣(LeetCode)
看到这一题的时候我也是一头雾水,但是看过灵神写的题解,才慢慢反应过来。

灵神首先给出的是暴力求解

对于方法一,其实我开始也看不明白代码什么意思

class Solution {
public:
bool queryString(string s, int n) {
for(int i=1;i<=n;i++)
{
auto bin = bitset<32>(i).to_string();
bin = bin.substr(bin.find('1'));
if(s.find(bin) == -1) return false;
}
return true;
}
};
这里使用gtp解释一下

对于方法二:

直接截图看灵神的解释吧,人家写的太详细了,想的太妙了,尤其是其中的(x << 1) | (c - '0')。

但是妙归妙,还是要看完思路,自己尝试首先一下代码。

class Solution {
public:
bool queryString(string s, int n) {
unordered_set ans;
for(int i=0,m=s.size();i<m;i++)
{
int x=s[i]-'0';
if(x==0) continue;// 二进制为,继续
for(int j=i+1;x<=n;j++)
{
ans.insert(x);
if(j==m) break;
x=(x<<1) | (s[j]-'0');
}
}
return ans.size()==n;
}
};
第六题:2269. 找到一个数字的 K 美丽值 - 力扣(LeetCode)

这道题要说它简答吧,直接暴力硬写也可以写出来,但是要说它简单,但要使用滑动窗口来写,又比较麻烦。

思路好想,没什么难度,直接给代码

class Solution {
public:
int divisorSubstrings(int num, int k) {
vector v; //存放num这个数串每个位的值
int n; //代表数串每个位数的值
int num1 = num; //将num赋给num1
int res = 0;//美丽值-返回的结果
while(num1 != 0){//从个位 十位 百位...依次压入v容器中
n = num1%10;//余数
num1 = num1/10;//自除更新num1
v.push_back(n);
}
reverse(v.begin(),v.end());//逆序v容器的元素
int left = 0;//左边界
int right = k-1;//右边界 //0到k-1正好k个数
for(left,right;right<v.size();right++,left++){//滑动窗口方式模拟验证
int tmp = v[left];//初始化tmp 滑动窗口左边界代表 窗口内数串的最高位
for(int i=left+1;i<=right;i++){
tmp = tmp*10+v[i]; //模拟滑动窗口中元素组成一个数
}
if(tmp == 0)//如果为0,直接下一次循环
continue;
if(num%tmp == 0 ) {//如果可整除,美丽值结果+1
res++;
}
}
return res;//返回结果
}
};
第七题: 1984. 学生分数的最小差值 - 力扣(LeetCode)

如果是在没有思路,那不妨先让其有序。

class Solution {
public:
int minimumDifference(vector& nums, int k) {
int ret=INT_MAX;
int n=nums.size();
sort(nums.begin(),nums.end());
for(int left=0,right=0;right<n;right++)
{
if(right-left+1==k)
{
ret=min(ret,(nums[right]-nums[left++]));
}
}
return ret;
}
};
没有解决的题目:

会员题除外

  1. 统计完全子字符串 - 力扣(LeetCode)

  2. 使二进制字符串字符交替的最少反转次数 - 力扣(LeetCode)

  3. 存在重复元素 III - 力扣(LeetCode)

目录
打赏
0
0
0
0
2
分享
相关文章
Docker centos7 中文乱问题解决方案
Docker centos7 中文乱问题解决方案
915 0
🧠 用 AI 提升你的编程效率 —— 在 PyCharm 中体验通义灵码
通义灵码是一款基于大模型的智能编程辅助工具,现已上线PyCharm插件V2.5+版本。它能根据自然语言描述、注释或上下文生成高质量代码,支持多语言(Python、Java等),提供代码补全、优化建议、单元测试生成及异常排查等功能。集成魔搭MCP市场3000+服务,具备编程智能体模式与长期记忆能力,助开发者提升效率。适用初学者、资深开发者及团队协作场景。小红书、B站、抖音、微博均有相关资源分享。 小红书: http://xhslink.com/a/SvabuxSObf3db bilibili:https://b23.tv/1HJAdIx 抖音: https://v.douyin.com/1DAG
778 3
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
137 0
在Linux下配置gitee与Github的远程仓库
注意,git push后,是输入你的账号与密码。这个步骤可以通过特殊设置省去,但是一开始还是不要太省。
112 0
解决Git中没有小绿勾与红叉叉的问题
找到下面这个地址:\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers。后产生的,要在圈住的这几个在前面,添加空格(右击重命名加空格就能使它提到前面)关于要添加几个空格的问题,一般来说添加四个或者八个就可以。然后,重启电脑就能产生小绿勾和红叉叉的图标了。运行完重启电脑就好使。注意这一步一定要操作对,操作错误就会很多麻烦。寻找与自己电脑相配的软件版本就可以了。
409 0
c++模板进阶操作——非类型模板参数、模板的特化以及模板的分离编译
在 C++ 中,仿函数(Functor)是指重载了函数调用运算符()的对象。仿函数可以像普通函数一样被调用,但它们实际上是对象,可以携带状态并具有更多功能。与普通函数相比,仿函数具有更强的灵活性和可扩展性。仿函数通常通过定义一个包含operator()的类来实现。public:// 重载函数调用运算符Add add;// 创建 Add 类的对象// 使用仿函数return 0;
92 0
set、map、multiset、multimap的介绍及使用以及区别,注意事项
set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。set默认是升序的,但是其内部默认不是按照大于比较,而是按照小于比较。set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。
127 0
Linux环境基础开发工具的使用(yum、vim、gcc、g++、gdb、make/Makefile)
本文介绍了yum 包管理工具、Vim 编辑器、gcc/g++ 编译器、gdb 调试器、编译原理及 Makefile 的使用,同时还配备了如何使用,以及图解。旨在帮助读者更好地理解和应用这些工具与技术。
110 0
|
2月前
|
C++
爱心代码 C++
这段C++代码使用EasyX图形库生成动态爱心图案。程序通过数学公式绘制爱心形状,并以帧动画形式呈现渐变效果。运行时需安装EasyX库,教程链接:http://【EasyX图形库的安装和使用】https://www.bilibili.com/video/BV1Xv4y1p7z1。代码中定义了屏幕尺寸、颜色数组等参数,利用随机数与数学函数生成动态点位,模拟爱心扩散与收缩动画,最终实现流畅的视觉效果。
97 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问