最长子串与滑动窗口
例题 力扣: 无重复字符的最长子串
题目描述:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
题解
暴力法与滑动窗口:
1、暴力法:遍历字符串,依次以每一个字符当做子串的头,找到当前字符作为子串头的最长子串。采用双重循环,外循环遍历字符串,内循环搜索当前不重复的最大子串。(仔细观察发现,每一个以当前字符作为头的最长子串与前一个字符为头的最长子串之间有重叠部分,抓住这个特点,提高效率)
2、滑动窗口:引入队列,记录以当前字符作为子串的头最大不重复子串。提高效率的地方在于:充分利用上一个最大不重复子串与当前最大不重复子串的“重叠部分”。
具体操作方法:比如例题中的 abcabcbb,窗口的右边界依次向右移动(窗口中的字符串满足要求时左边界保持不动)。右边界移到c处时,窗口中abc 满足要求,当再进入 a,变成了 abca,这时候不满足要求。此时要改变窗口以满足要求:将窗口的左边界向右移动,直到符合要求(将冲突元素移除窗口:bca)。可以把窗口用队列比较容易实现。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int maxlen=0;
unordered_set<char> tems;//窗口中的字符串
int len=s.length();
int left=0,right=0;
while(left<len&&right<len)
{
if(tems.find(s[right])==tems.end())//s[right]与窗口中的子串不冲突
{
tems.insert(s[right++]);
}
else//有重复时
{
do{
tems.erase(s[left]);
left++;
}while(tems.find(s[right])!=tems.end());//移动窗口左边界直至满足要求
}
maxlen=max(maxlen,int(tems.size()));
}
return maxlen;
}
};
例题2力扣1004最大连续1的个数
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
示例 1:
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:
[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
解法:
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int countR=0;
int start=0,end=0;
int len=nums.size();
// int maxlen=0;
while(end<len&&start<len)
{
//解法一
// if(nums[end]==0)
// {
// // countRi.push_back(end);
// countR++;
// }
// end++;
// while(countR>k)
// {
// // start=countRi.front()+1;
// // countRi.pop_front();
// if(nums[start++]==0)
// countR--;
// }
// maxlen=max(maxlen,end-start);
//解法二:滑动窗口的平移与扩张思想。
if(nums[end++]==0)
{
countR++;
}
if(countR>k)//当count<=k时扩张(左边界不动,右边界+1)
//当countR>k时,左边界+1,右边界+1相当于平移窗口。
//时刻保持以当前符合要求的最大窗口搜索
{
if(nums[start++]==0)
{
countR--;
}
}
}
return end-start;
}
};