算法入门---专题二:滑动窗口2(最大连续1的个数,无重复字符的最长子串 )
🎬 胖咕噜的稞达鸭:个人主页

最大连续1的个数
最大连续1的个数

- 题目描述
数组nums中,给定一个整数k,如果最多翻转k个0,要求返回数组中连续1的最大个数。
这里我们给定一个示例:【 1,1 , 1 , 0 , 0, 0, 1, 1 , 1, 1, 0】 - 算法原理:
解法一:双指针+暴力枚举+counter计数器
双指针:定义一个left和right指针,先让left在索引为0的位置,right指针向后走,counter计数器的作用是指针在 走的过程中遇到nums[ptr]==1,直接走++到下一个位置,遇到nums[ptr]==0,要将0放到counter中,当counter中记录的0的个数大于k了,就需要让数组中的0翻转为1,再将【left,right】这段区间里面的1的个数记录入ret中,ret用于存储每一次翻转之后的左右区间中的1的个数,每一次记录了新的左右区间,都要将right-left+1和上一次的ret进行比较,只留下最大的那一个。
暴力枚举,right走到了一个位置,这个位置的数字是0,但是此时counter中已经有等于k个0了,此时left从原来索引为0的位置,走向索引为1,right要退回去,退到索引为0的位置重新开始,这样属于重复操作了,所以进行优化的办法就是让right不用回退,减少算法的执行复杂度------滑动窗口。来进行优化:解法二
解法二:滑动窗口+counter计数器
解法二作为优化解法一,同样也是定义一个right和left,相对比暴力枚举,在优化的地方:right不用回退,如果找到了counter>k,就让left开始向后走,遇到nums[left]==1,left++向后走不进行操作,遇到nums[left]==0,counter--,删除counter中的0,然后让left走到下一个位置开始新一轮的左右区间(如果left没有走到下一个区间,还是处在left==0的位置,就意味着区间中天然多了一个0)。
总结:
如果right遇到的数字等于0,就需要进窗口,如果counter大于k,就需要出窗口,让left向后走,遇到0,计数器中的0要减少一个,最后返回每一次更新的ret的最大值。
class Solution {
public:int longestOnes(vector<int>& nums, int k) {int ret=0;for(int left=0,right=0,counter=0;right<nums.size();right++){//进窗口,当right指向的数字等于0就形成了有效的滑动窗口if(nums[right]==0)counter++;//出窗口,如果counter中的0大于k,那就需要left向后遍历,left指向的数字等于1,不做处理,等于0要counter--,此时left到right的区间内已经多了一个0,left的位置向后++一个位置while(counter>k){if(nums[left++]==0) counter--;}//出窗口ret=max(ret,right-left+1);}return ret;}
};
无重复字符的最长子串
无重复字符的最长子串

-
题目解析:
找出字符串中不含重复字符的最长子串的长度。 -
算法原理:
解法一:暴力枚举
给定两个指针right,left,left和right从索引为0的位置开始,right先走,将nums[right]计入哈希表中,所以首先要定义一个数组来模拟哈希表,这里我们申请128个空间用来存储right遍历中遇到的字符,每走一步都要检查哈希表中有没有相同的字符出现,哈希表中没有重复的字符出现,right++,如果哈希表中出现了重复的字符,那就说明,需要出窗口,此时让left++,right退回到索引为1的位置,继续开始遍历,解法二:讲解right不用回退。
解法二:滑动窗口
right走到的位置出现了哈希表中相同的字符,此时从left到right的前一个位置,算是数组中的一个不含有重复字符的字串。当哈希表中出现了重复的字符,此时left开始向后走,遇到哈希表中重复的符字,就从哈希表中删除,然后再走向下一个位置(不然数组中又多了一个即将重复的字符),此时更新一下ret,从每一段right-left+1的长度和已经有的ret进行比较,谁大谁就当作时新的ret。
总结:
right向后开始遍历,每遇到一个从未出现在哈希表中的字符,就计入哈希表中,进窗口;当哈希表中出现了重复的符字,让left向后遍历,遇到重复出现在哈希表中的字符,就从哈希表中删除,出窗口。
- 上代码!
class Solution {
public:int lengthOfLongestSubstring(string s) {//用数组模拟哈希表int hash[128]={0};//申请128个空间,每个空间都初始化为0//思路:定义一个left,right从索引为0的位置开始遍历//先让right不断向后走//寻找哈希表中有没有相同的元素,如果有的就停止,计算从left到right这段区间的长度//然后出窗口,left移动到第一个重复的字符的后一个位置,不用再让right走回来//一直让right遍历到最后一个位置int left=0, right=0 , n=s.size();int ret=0;while(right<n){hash[s[right]]++;//进入窗口while(hash[s[right]]>1)//判断统计次数,如果出现次数大于1,就说明重复了hash[s[left++]]--;//出窗口,先--,将这个字符从哈希表中删除,再++,left的位置走到一重复位置的下一个位置,继续进入哈希表ret=max(ret,right-left+1);//从每一段right-left+1的长度和已经有的ret进行比较,谁大谁就当作时新的retright++;//让下一个元素进入窗口}return ret;}};

