【C/C++算法】从浅到深学习---滑动窗口(图文兼备 + 源码详解)
绪论:冲击蓝桥杯一起加油!!
每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry”
绪论:
本章是算法训练的第二章----滑动窗口,它的本质是双指针算法的衍生所以我将他们放到了连续的篇章,若看完双指针算法再来看本章会相对来说轻松点(传送阵),后续还将继续持续更新算法(三天一更),直到蓝桥杯结束,敬请期待~
————————
早关注不迷路,话不多说安全带系好,发车啦(建议电脑观看)。
滑动窗口
本质其实是使用双指针暴力解法,控制移动指针下标的方式得到一片区间,类似像一个窗口,并且这个双指针在移动过程中若从分析题目得知其单调性让指针始终从左往右的移动,那么该双指针所指向的区间就是滑动窗口!
记住:
滑动窗口就是暴力双指针解法衍生出来的,一般分析出left、right指针都是一直往右移的那么就表示为滑动窗口
在解题时若见:连续子数组(子串),一般都可以尝试用滑动窗口算法
滑动窗口具体怎么用
最基本模板
1. left = 0,right = 0
2. 进窗口(维护窗口的信息)
3. 判断(根据窗口 信息判断 是否出窗口,可能为循环一次出多个窗口)1. 出窗口更新结果(位置不固定!)
根据题目放到合适的位置(这个多练几道题就能很轻松的掌握了)
如下图:
正确性:因为是利用单调性分析得出的他们同时像右移并且不用向左移动,规避了很多没必要的枚举行为,所以本质是分析出来的,就题论题!
时间复杂度:双指针始终都是往右移的,最大情况:n + n = 2n = O(N)
具体训练:
1. 长度最小的子数组
题目:
分析题目并提出,解决方法:
暴力解法:将所有子数组遍历出来,当遍历到一个区间后计算结果(如下图)
但这样遍历(时间复杂度:N2)* 计算结果(N)(就会导致时间复杂度非常大O(N3),记住:像这种不断增加的线性区间,可以提前将每个区间的值算出来,然后存储在数组中(前缀和但此处仅仅浅浅的用了下,后面就会更新详细前缀和算法!),这样对计算结果的过程就能被优化为常数时间复杂度)
具体优化方法如下:
先遍历一遍,为了计算区间的值:
使用sum记录 left ~ right 区间的值,right每走一步就加上一步的值
并且我们遍历的过程,也不是无脑的遍历==,而是当结果一定不可是后面区间后,那么就直接跳过不算了(如下)==
而此时发现:right不用再移动回来了(因为在移动虽然满足条件但len长度一定会增大)
从而可以让left移动一步继续遍历其他区间
- 因为这段区间的值可以快速的算出来只需要sum - left位置的值即可
- 所以也得知他其实就是滑动窗口
最终我们就能通过滑动窗口的基本模板来遍历这个数组,最终得到如下图滑动窗口移动过程:
直到最后right移动到最后:
为何滑动窗⼝可以解决问题,并且时间复杂度更低?
- 这个窗⼝寻找的是:以当前窗⼝最左侧元素(记为 left1 )为基准,符合条件的情况。也 就是在这道题中,从 left1 开始,满⾜区间和 sum >= target 时的最右侧(记为right1 )能到哪⾥。
- 我们既然已经找到从 left1 开始的最优的区间,那么就可以⼤胆舍去 left1 。但是如 果继续像⽅法⼀⼀样,重新开始统计第⼆个元素( left2 )往后的和,势必会有⼤量重复 的计算(因为我们在求第⼀段区间的时候,已经算出很多元素的和了,这些和是可以在计算 下次区间和的时候⽤上的)。
- 此时, rigth1 的作⽤就体现出来了,我们只需将 left1 这个值从 sum 中剔除。从right1 这个元素开始,往后找满⾜ left2 元素的区间(此时 right1 也有可能是满 ⾜的,因为 left1 可能很⼩。 sum 剔除掉 left1 之后,依旧满⾜⼤于等于target )。这样我们就能省掉⼤量重复的计算。
- 这样我们不仅能解决问题,⽽且效率也会⼤⼤提升。 时间复杂度:虽然代码是两层循环,但是我们的 left 指针和 right 指针都是不回退的,两者 最多都往后移动 n 次。因此时间复杂度是 O(N)。
题解核心逻辑(源码):
诸多细节已注释到代码中(见下):
class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {// 通过暴力解法,分析题目可知我们可以使用滑动窗口,也就是left right双指针都只需要往右移,不用恢复回来(向左移)int sum = 0,res = INT_MAX;//循环for(int left = 0,right = 0;right < nums.size();right++){//进窗口://本质就是将right下标指向的值,添加到sum计数器中sum += nums[right];//并且right向后移动 ++//判断://一般来说都是判断是否需要出窗口,本题也就是判断,sum 是否大于 target,若大于了就需要出窗口了//该判断也是一定要按题意来的,本题对于大于等于target的值后就不再需要往后遍历了,所以就出窗口//所以我们需要知道什么时候出窗口,它的具体条件是什么!while(sum >= target){//记录答案://记录答案一般来说就是最大或最小值//一般来说都是查看当前区间的值 是否满足最大或者最小,若满足就保存否则跳过//本题是找最小的长度,所以说我们需要判断该区间是否最小res = min(res,right - left + 1);//出窗口://就比较简单一般来说就是将left上的值从当前区间,sum计数器中减去//本质:也就是记录之前的值,然后要更新成新的值了//减去left的值,并让left移动,形成新的区间sum -= nums[left];left++;}}return res == INT_MAX ? 0 : res;}
};
2. 无重复字符的最长子串
题目:
分析题目并提出,解决方法:
通过上图就能很快的认知到题目的目的:
找到一个最长不包含重复字符的字串
暴力解法很好想:遍历呗,遍历所有情况最终记录最短的即可,但能不能优化呢?
其中不难发现条件中的不能出现重复,那么在我们遍历的过程中,若出现了重复的是不是就可以把之前的记录了,然后再舍弃最后得到新满足的区间,在继续往后记录查找。
那如何快速的判断是否出现重复字符呢?
hash表!,通过在遍历的过程中,通过hash表记录遍历过的字符,当hash中对应字符的值大于1后就表示出现了重复!!
题解核心逻辑:
当区间出现重复字符的时候left就需要往移,但只移动一步的话,很明显right肯定还将碰到重复的值(对于上图来说),所以说我们需要将left移动到重复值的下一个位置:
right不用回来继续往右移即可,因为left就是将重复的给跳过了,所以区间中一定不会出现重复的了
那么到此就发现它又是一个:滑动窗口!
那么就结合滑动窗口的基本模板,就本题分析修改判断以及进窗口出窗口该怎么写!
分析得出:
class Solution {
public:int lengthOfLongestSubstring(string s) {if(s.size() == 0) return 0;int hash[128] = {0};int res = INT_MIN;for(int left = 0,right = 0;right < s.size() ; right++){//进窗口hash[s[right]]++;//针对s[right]字符进窗口//判断,若出现重复字符while(hash[s[right]]>1){//出窗口hash[s[left]]--;left++;}//每次都记录,这次不再内部记录,是因为进去后是出现了重复了字符了,记录的长度就不对了//他不想上一题有冗余度:大于等于target都行res = max(res,right - left + 1);}return res;}
};
3. 最大连续1的个数 III
题目:
分析题目并提出,解决方法:
分析暴力解法:
- 可以用双指针来确定连续的1的区间,然后对于可翻转0通过记录个数zero
- 当zero个数大于k后,代表区间不满足条件了,right就不能移动,需要移动left。
- 再重新遍历所有新区间,最终得到所有情况。
具体如下图:
当正常枚举时zero的个数为k后,则right就不能再继续往后了,该left移动了
优化:
而left若只移动一步则left ~ right 区间内 的zero还是等于k(如上图),那么长度肯定不会增加,right就没有必要重新回来枚举。
所以left一个不断移动直到让 left ~ right 区间内zero不等于k
再继续移动right,此处就有可知left right都是一直往右移动,所以可以使用滑动窗口
题解核心逻辑:
最终得出滑动窗口模板分析(如下图:)
class Solution {
public:int longestOnes(vector<int>& nums, int k) {int zero = 0,res = 0;for(int left = 0,right = 0; right < nums.size();right++){//进窗口if(nums[right] == 0){zero++;}//判断,当0的个数大于了k,表示子数组不符合条件了while(zero > k){//出窗口if(nums[left] == 0){zero--;}left++;}res = max(res,right - left + 1);}return res;}
};
4. 将 x 减到 0 的最小操作数
题目:
分析题目并提出,解决方法:
题目要求找到从左右最少次数删除得到0
但若直接从正面想,每次左右删除可能性非常多,非常难写(到底先左还是先右)
此时我们可以反过来思考下:
正难则反
既然想两边比较困难,那么在线性中,选择了两左右两边,那么中间就是单独出来的!
那么就转换成了找 最长、子数组 的长度,所有元素的和正好等于target(sum - x)
不难发现它和我们之前做的第一题相反(1. 长度最小的子数组)
题解核心逻辑:
那么就可以尝试用双指针遍历所有区间查找
当left ~ right 区间大小大于等于target
此时right不用再移动了,因为需要找的事刚好等于target,在移动只会更大
所以需要移动left:
但移动left后,right不需要再回来重新遍历,因为只会更小
所以right和left都是始终向右移动的,也就是滑动窗口
class Solution {
public:int minOperations(vector<int>& nums, int x) {//分析得知使用滑动窗口找到值为 target (nums所有值 - x) d 最大连续子数组int target = accumulate(nums.begin(),nums.end(),0) - x;int n = nums.size();if(target < 0) return -1;int sum = 0,len = -1;for(int left = 0,right = 0;right < n;right++){//进窗口sum += nums[right];//sum存储值,找值为target的最大连续子数组//判断:while(sum > target){//出窗口sum -= nums[left];if(left < n){left++;}}//记录结果,找到值为target就记录一下if(sum == target){len = max(len,right - left + 1);}}if(len == -1){return -1;}return n - len;}
};
5. 水果成篮
题目:
分析题目并提出,解决方法:
分析题目,可知题目所需为:在数组中找到最长的子数组,并且水果类型不超过两种,就很有滑动窗口的特性,所以我们直接上滑动窗口
题解核心逻辑:
使用双指针
当left右移后:水果类型kinds的变化
不难发现right没有必要回来到left位置重新(左移)遍历,而事等待水果个数变小(left移动)后再继续右移
所以:left、right都是始终保持右移的,也就是滑动窗口!
算法原理:
class Solution {
public:int totalFruit(vector<int>& fruits) {int kinds = 0;//记录水果类型个数int hash[100010] ={ 0};//记录水果出现次数int res = 0;//结果//最终要找的是最大的子数组长度for(int left = 0,right = 0;right < fruits.size();right++){//进窗口。水果的个数小于2时if(kinds <= 2){if(hash[fruits[right]] == 0){kinds++;//如果水果没有出现过 类型就要++}hash[fruits[right]]++;}//当水果类型超过2种的时候就要出窗口了while(kinds > 2){hash[fruits[left]]--;if(hash[fruits[left]] == 0){kinds--;}left++;}res = max(res,right - left + 1);}return res;}
};
6. 找到字符串中所有字母异位词
题目:
分析题目并提出,解决方法:
分析题目可知本题题意为:
判断两个字符串是否是异位词(字符相同可能顺序不同):
直接通过两个hash表,存储着他们各自字符的个数,然后比较这些个数是否相同即可知道字符串是否相同,若个数相同则代表元素相同只不过顺序不同!
题解核心逻辑:
这样我们就能得知方法:
暴力解法:
- 先获取目标字符串个数
- 使用双指针指向该相同个数的字符串区间
- 移动遍历,比较一下和目标字符串中的元素个数是否都相同
- 其中不难看出来left ~ right区间中right其实不需要回来,因为长度是固定的,所以该区间只需要不断往前,也就是left、right不断++,最终就能遍历所有区间。
所以因为left、right不断++,所以也就是滑动窗口:
class Solution {
public:bool Check(int hash1[26],int hash2[26]){for(int i = 0;i < 26;i++){if(hash1[i] != hash2[i]){return false;}}return true;}vector<int> findAnagrams(string s, string p) {int hash1[26] = {0};//存储滑动窗口中元素的个数int hash2[26] = {0};//存储目标个数for(auto c : p){hash2[c-'a']++;}vector<int> res;for(int left = 0,right = 0;right < s.size(); right++){//进窗口hash1[s[right] - 'a']++;if(right - left + 1 > p.size()){hash1[s[left] - 'a']--; left++;}if(Check(hash1,hash2)){res.push_back(left);}}return res;}
};
其中对于Check检查字符串是否为异位词函数来说,本质也还是遍历两个数组26次,虽然微不足道,但还能优化,具体如下:
其中使用count记录有效字符个数,何为有效?
- 在滑动窗口滑动的过程中,窗口内的元素决定了有效字符个数
- 有效字符:
- 根据题意要找的是对应字符串中的相同字符
- 那么在滑动窗口中
- 进窗口:
- 若进窗口的字符和对应字符串中的某个字符相等(字符相等)
- 且窗口内的已有个数小于等于对应窗口中的个数(个数小于等于)
- 有效的,count++
- 反之不有效count不变
- 出窗口:
- 同样也需要判断出窗口的字符是否是有效字符
- 若是则需要修改count–
- 当count == 对应字符串中的个数,即代表刚好找到了,那么就更新结果
- 总结就是使用一个count有效字符计数器来判断是否找到了
优化后代码:
class Solution {
public:vector<int> findAnagrams(string s, string p) {int hash1[26] = {0};//存储滑动窗口中元素的个数int hash2[26] = {0};//存储目标个数int count = 0;for(auto c : p) hash2[c-'a']++;vector<int> res;for(int left = 0,right = 0;right < s.size(); right++){//进窗口hash1[s[right] - 'a']++;if(hash1[s[right] - 'a'] <= hash2[s[right] - 'a']){count++;}if(right - left + 1 > p.size()){if(hash1[s[left] - 'a'] <= hash2[s[left] - 'a']){count--;}hash1[s[left] - 'a']--;left++;}if(count == p.size()){res.push_back(left);}}return res;}
};
7. 串联所有单词的子串
题目:
分析题目并提出,解决方法:
分析题目画出下图:
理解题目所需:从s中找到w字符串数组的不同排列情况
如下图:w : “foo”、“bar”
那么s中符合条件的如下画横线处:
通过图像我们不难看出假设,把s和w中的字符串以其s内部的字符串长度为划分看出一个个字符:
那么就将变成如下图形式:
那么本题就很前面走的一题非常相似:找异位词!
所以使用同样的方法,只不过此时left和right的移动需要改变从w中字符串长度
其中注意的是:
要遍历所有情况,也就是改变left的起始位置 [ 0 ~ len),这样才能遍历所有情况,具体如下不同颜色的横线
题解核心逻辑:
核心逻辑和找异位词一致:
不同的是:
- left和right的移动长度需要修改
- 比较时通过hash存储字符比较相同
- 在最外层增加一个循环顾忌所有情况
更多细节见源码:
class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {//分析可知本题和字母异位词很像,类似:将字符串看成字符vector<int> res;unordered_map<string,int> hash2;//存储words中个数int n_hash2 = 0;for(auto& s : words){n_hash2++;hash2[s]++;}int len = words[0].size();for(int i = 0 ; i < len; i++){//注意 hash1 、 count 需要放到内部,初始化,防止下一次遍历使用到上次的数据unordered_map<string,int> hash1;//存储个数int count = 0;//同样使用 有效字符记录for(int left = i,right = i;right < s.size();right += len){string sub1 = s.substr(right,len);//进窗口hash1[sub1]++;// hash2.count(sub1) 避免 hash2[sub1] 内部数据不存在时的创建该数据的消耗if( hash2.count(sub1) && hash1[sub1] <= hash2[sub1]){count++;}//判断是否出窗口,窗口中的个数是否大于所找的字符串个数// 画图可知:((right - left) / len) + 1 为当前滑动窗口元素个数// n_hash2 为所找的字符串的元素个数if(((right - left) / len) + 1 > n_hash2){string sub2 = s.substr(left,len);//if(hash2.count(sub2) && hash1[sub2] <= hash2[sub2]){count--;}hash1[sub2]--;//出窗口left += len;}if(count == n_hash2){res.push_back(left);}}}return res;}
};
8.最小覆盖子串
题目:
分析题目并提出,解决方法:
分析题目可知本题:从s字符串中找到最短的包含t字符串中所有字符的子串
如下图:ADOBEC(就包含了所有t:ABC)、BECODEBA(同样也包含所有)、BANC
其中不难看出BANC最短,所以他就是最终答案
具体如下图:
那么就能推出,暴力解法:使用双指针遍历所有区间,并且使用哈希表来判断是否已经包含t字符串了
但我们再暴力解法的情况下再分析,看看是否符合滑动窗口:
不难发现下面情况:
right没必要回去了,因为只有两种可能:
- left 右移区间改变,但仍然符合条件,那么right移动回来,再往右找,最终还会移动到相同的为止停下来(因为条件没变,right指向的地方仍然是最后一个值)
- 若left右移区间改变,但不符合条件了,那么right肯定会移动到原来位置再往右的位置才可能停下
题解核心逻辑:
那么就是滑动窗口了:
分析题意的下面滑动窗口模板:
优化:
同样是使用一个count进行记录有效字符个数,代替使用hash表的比较记录,但本题中他的条件不要一样,并不需要找到异位词,而是找到包含t中所有字符的即可,而其中相同的字符可能会出现多次,所以count只有在 滑动窗口中某个元素的个数 = 目标字符串的某个元素的个数时才++和–,因为假如 count 是 >= 目标个数(肯定不是小于,小于不符合个数大于等于条件)时都 ++ 的话那么可能会多算
记住count是有效字符个数,我们要结合好题目所给的条件进行设置!(此题见题目中的注意事项可知:“不少于”)
class Solution {
public:string minWindow(string s, string t) {unordered_map<char,int> hash1;//存储滑动窗口内部数据unordered_map<char,int> hash2;//存储t字符中的元素for(auto c : t) hash2[c]++;int count = 0;//维护一个有效字符个数计数器i、nt len = INT_MAX;//用于比较长度,找到最小的长度int l_res = -1;for(int left = 0,right = 0; right < s.size() ;right++){//进窗口hash1[s[right]]++;//hash2.count(s[right])这里是防止hash2[s[right]]创建新的字符if(hash2.count(s[right]) && hash1[s[right]] == hash2[s[right]]) count++;//判断while(count == hash2.size()){//记录if(right - left + 1 < len){len = right - left + 1;l_res = left;}//出窗口if(hash2.count(s[left]) && hash1[s[left]] == hash2[s[left]]) count--;hash1[s[left]]--;left++;}}if(l_res == -1) return "";return s.substr(l_res,len);}
};不使用容器:
class Solution {
public:string minWindow(string s, string t) {int hash1[128] = {0};//存储滑动窗口内部数据int hash2[128] = {0};//存储t字符中的元素int kinds = 0;for(auto c : t) {if(hash2[c] == 0) kinds++;//若果为0代表新类型hash2[c]++;}int count = 0;//维护一个有效字符个数计数器int len = INT_MAX,begin = -1;//len记录最小的长度、begin记录最小长度的起始位置for(int left = 0,right = 0; right < s.size() ;right++){//进窗口hash1[s[right]]++;if(hash1[s[right]] == hash2[s[right]]) count++;//判断while(count == kinds){//记录,找到新的小的长度if(right - left + 1 < len){len = right - left + 1;begin = left;}//出窗口if(hash1[s[left]] == hash2[s[left]]) count--;hash1[s[left]]--;left++;}}if(begin == -1) return "";return s.substr(begin,len);}
};
相关文章:

【C/C++算法】从浅到深学习---滑动窗口(图文兼备 + 源码详解)
绪论:冲击蓝桥杯一起加油!! 每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章是算法训练的第二章----滑动窗口,它的本质是双指针算法的衍生所以我将…...

计算机毕业设计SpringBoot+Vue.js房源推荐系统 房价预测 房源大数据分析可视化(源码+文档+运行视频+讲解视频)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
开源机器人+具身智能 解决方案+AI
开源机器人、具身智能(Embodied Intelligence)以及AI技术的结合,可以为机器人领域带来全新的解决方案。以下是这一结合的可能方向和具体方案: 1. 开源机器人平台 开源机器人平台为开发者提供了灵活的基础架构,可以在此基础上结合具身智能和AI技术。以下是一些常用的开源机…...

通过 VBA 在 Excel 中自动提取拼音首字母
在excel里面把表格里的中文提取拼音大写缩写怎么弄 在Excel中,如果你想提取表格中的中文字符并转换为拼音大写缩写(即每个汉字的拼音首字母的大写形式),可以通过以下步骤来实现。这项工作可以分为两个主要部分: 提取拼…...

华硕笔记本怎么一键恢复出厂系统_华硕笔记本一键恢复出厂系统教程
华硕笔记本怎么一键恢复出厂系统? 华硕一键恢复出厂系统是一个安全、高效、方便的恢复方式,让您轻松还原出厂设置,以获得更好的系统性能。如果您的华硕电脑遇到问题,可以使用华硕一键恢复出厂系统功能。下面小编就教大家华硕笔记本…...

Ubuntu 如何安装Snipaste截图软件
在Ubuntu上安装Snipaste-2.10.5-x86_64.AppImage的步骤如下: 1. 下载Snipaste AppImage 首先,从Snipaste的官方网站或GitHub Releases页面下载Snipaste-2.10.5-x86_64.AppImage文件。 2. 赋予执行权限 下载完成后,打开终端并导航到文件所在…...
【离散数学上机】T235,T236
T235题目:输入集合A和B,输出A到B上的所有单射函数。 问题描述 给定非空数字集合A和B,求出集合A到集合B上的所有单射函数。 输入格式 第一行输入m和n(空格间隔),分别为集合A和集合B中的元素个数;…...
【Android开发】安卓手机APP使用机器学习进行QR二维码识别(完整工程资料源码)
前言:本项目是一个 Android 平台的二维码扫描应用,具备二维码扫描和信息展示功能。借助 AndroidX CameraX 库实现相机的预览、图像捕获与分析,使用 Google ML Kit 进行二维码识别。为方便大家了解项目全貌,以下将介绍项目核心代码文件 MainActivity.java 和 AndroidManifes…...

【油猴脚本/Tampermonkey】DeepSeek 服务器繁忙无限重试(20250214优化)
目录 一、 引言 二、 逻辑 三、 源代码 四、 添加新脚本 五、 使用 六、 BUG 七、 优化日志 1.获取最后消息内容报错 2.对话框切换无法正常使用 一、 引言 deepseek演都不演了,每次第一次提问就正常,后面就开始繁忙了,有一点阴招全…...
为deepseek搭建本地页面
搭建页面的框架多种多样,例如python中的flask、django等,再如java中的spring框架等等。你使用什么语言、什么框架都无所谓,重要的是设计思路。这里UP以node.js中的express框架为例来为deepseek搭建一个本地页面。 一、ollama的下载、安装和加载 deepseek本地部署-CSDN博客…...

详解df -h命令
df -h 是 Linux 中用于查看文件系统磁盘空间使用情况的命令。以下是详细说明: 命令格式 df -h 选项说明 -h:以易读格式(如 KB、MB、GB)显示磁盘空间。 输出字段 Filesystem:文件系统的设备名或挂载点。 Size&…...
虚拟环境测试部署应用
一、作用 虚拟环境(env)在计算机领域,特别是在软件开发和测试中扮演着重要角色。它主要用于创建一个隔离的环境,使得开发者可以在不影响系统其余部分的情况下安装、配置和运行软件项目。以下是虚拟环境的一些主要作用: 1、依赖管理 不同的项目可能需要不同版本的库或框…...
CentOS本机配置为时间源
CentOS本机配置为时间源 安装chrony,默认已安装修改配置文件 /etc/chrony.conf客户端配置 安装chrony,默认已安装 yum -y install chrony修改配置文件 /etc/chrony.conf # cat /etc/chrony.conf | grep -Ev "^$|#" server ceph00 iburst dri…...
蓝桥杯备赛 Day14 素数环
信息学奥赛一本通(C版)在线评测系统 【题目描述】 输入正整数nn,把整数11,22,…,nn 组成一个环,使得相邻两个整数之和均为素数。 【输入】 输入正整数nn。 【输出】 输出任意一个满足条件的环。 【输入样例】 6 【输出样例】 …...

小程序canvas2d实现横版全屏和竖版逐字的签名组件(字帖式米字格签名组件)
文章标题 01 功能说明02 效果预览2.1 横版2.2 竖版 03 使用方式04 横向签名组件源码4.1 html 代码4.2 业务 Js4.3 样式 Css 05 竖向签名组件源码5.1 布局 Html5.2 业务 Js5.3 样式 Css 01 功能说明 技术栈:uniapp、vue、canvas 2d 需求: 实现横版的全…...

haproxy详解笔记
一、概述 HAProxy(High Availability Proxy)是一款开源的高性能 TCP/HTTP 负载均衡器和代理服务器,用于将大量并发连接分发到多个服务器上,从而提高系统的可用性和负载能力。它支持多种负载均衡算法,能够根据服务器的…...
SpringCloud框架下的注册中心比较:Eureka与Consul的实战解析
摘要 在探讨SpringCloud框架中的两种注册中心之前,有必要回顾单体架构与分布式架构的特点。单体架构将所有业务功能集成在一个项目中,优点是架构简单、部署成本低,但耦合度高。分布式架构则根据业务功能对系统进行拆分,每个模块作…...

前端调用串口通信
项目录结构 node项目 1) 安装serialport npm install serialport 2)编写index.js 1 const SerialPort require(serialport); 2 var senddata [0x02];//串口索要发送的数据源 3 var port new SerialPort(COM3);//连接串口COM3 4 port.on(open, fun…...

23、深度学习-自学之路-激活函数relu、tanh、sigmoid、softmax函数的正向传播和反向梯度。
在使用这个非线性激活函数的时候,其实我们重点还是学习的是他们的正向怎么传播,以及反向怎么传递的。 如下图所示: 第一:relu函数的正向传播函数是:当输入值(隐藏层)值大于了,就输出…...

《8天入门Trustzone/TEE/安全架构》
CSDN学院课程连接:https://edu.csdn.net/course/detail/39573...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...

【Java多线程从青铜到王者】单例设计模式(八)
wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本,sleep也是可以指定时间的,也就是说时间一到就会解除阻塞,继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒),wait能被notify提前唤醒…...