目录
209.长度最小的子数组
题目:
给定一个含有 n 个正整数的数组和一个正整数 target 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3]
是该条件下的长度最小的子数组。
思想:所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
这其实也是 双指针 的一种。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size() - 1;
int k = 0 ;
int sum = 0 ;
int maxsum = INT32_MAX ;
for ( int i = 0 ;i <= n ; i++){
sum += nums[i] ;
while (sum >= target){
int sublength =( i - k + 1 );
maxsum = maxsum > sublength ? sublength : maxsum;
sum -= nums[k];
k++;
}
}
return maxsum == INT32_MAX ? 0 : maxsum ;
}
};
这里有个注意点: 为什么要用 while 而不是 if 。
相关题目:
904:水果成篮。
题目:
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
思路:维护left和right,每次取两个数作为基准,right向右滑动 ··如果fruits[right]不是其中的就更新新的数为基准将left直接移动到right前面一格,然后再向前找left相等的最前面的定位left。 ··如果fruits[right]是其中的就更新ans 。438
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int left = 0,right = 0,ans = 0;
int ln = fruits[left], rn = fruits[right];
while(right < fruits.size()){
if(fruits[right] == rn || fruits[right] == ln){
ans = max(ans,right + 1 - left);
right++;
}else{
left = right - 1;
ln = fruits[left];
while(left >= 1 && fruits[left - 1] == ln) left--;
rn = fruits[right];
ans = max(ans,right + 1 - left);
}
}
return ans;
}
};
438:找出字符串中的异位词
题目:
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
方法一:滑动窗口
思路
根据题目要求,我们需要在字符串 ss 寻找字符串 pp 的异位词。因为字符串 pp 的异位词的长度一定与字符串 pp 的长度相同,所以我们可以在字符串 ss 中构造一个长度为与字符串 pp 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;当窗口中每种字母的数量与字符串 pp 中每种字母的数量相同时,则说明当前窗口为字符串 pp 的异位词。
自己答案:
错误点:push_back 忘记书写,中间短杆
14~16行代码,为什么要书写?
第14行代码,为什么不能写等于?
第18行代码,如何定义,且为什么 right 可以书写 等于号。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> res;
if(s.size() < p.size()) return res;
vector<int> p_count(26);
vector<int> s_count(26);
for (int i = 0 ; i <= p.size()-1 ; i++){
p_count[p[i] - 'a']++;
}
for (int j = 0 ; j < p.size()-1 ; j++){
s_count[s[j] - 'a']++;
}
for (int left=0, right=p.size()-1;right<=s.size()-1;left++,right++){
s_count[s[right] - 'a']++;
if(s_count == p_count){
res.push_back(left);
}
s_count[s[left] - 'a' ]--;
}
return res;
}
};
官方答案:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int sLen = s.size(), pLen = p.size();
if (sLen < pLen) {
return vector<int>();
}
vector<int> ans;
vector<int> sCount(26);
vector<int> pCount(26);
for (int i = 0; i < pLen; ++i) {
++sCount[s[i] - 'a'];
++pCount[p[i] - 'a'];
}
if (sCount == pCount) {
ans.emplace_back(0);
}
for (int i = 0; i < sLen - pLen; ++i) {
--sCount[s[i] - 'a'];
++sCount[s[i + pLen] - 'a'];
if (sCount == pCount) {
ans.emplace_back(i + 1);
}
}
return ans;
}
};
方法二:优化的滑动窗口
思路和算法
在方法一的基础上,我们不再分别统计滑动窗口和字符串 p 中每种字母的数量,而是统计滑动窗口和字符串 p 中每种字母数量的差;并引入变量 {differ} 来记录当前窗口与字符串 p 中数量不同的字母的个数,并在滑动窗口的过程中维护它。
在判断滑动窗口中每种字母的数量与字符串 p 中每种字母的数量是否相同时,只需要判断 {differ} 是否为零即可:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int sLen = s.size(), pLen = p.size();
if (sLen < pLen) {
return vector<int>();
}
vector<int> ans;
vector<int> count(26);
for (int i = 0; i < pLen; ++i) {
++count[s[i] - 'a'];
--count[p[i] - 'a'];
}
int differ = 0;
for (int j = 0; j < 26; ++j) {
if (count[j] != 0) {
++differ;
}
}
if (differ == 0) {
ans.emplace_back(0);
}
for (int i = 0; i < sLen - pLen; ++i) {
if (count[s[i] - 'a'] == 1) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同
--differ;
} else if (count[s[i] - 'a'] == 0) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同
++differ;
}
--count[s[i] - 'a'];
if (count[s[i + pLen] - 'a'] == -1) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同
--differ;
} else if (count[s[i + pLen] - 'a'] == 0) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同
++differ;
}
++count[s[i + pLen] - 'a'];
if (differ == 0) {
ans.emplace_back(i + 1);
}
}
return ans;
}
};
76: 最小覆盖字串。
示例:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
思路:滑动窗口。
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char , int > hs , ht;
string ans;
for (int i = 0 ; i < t.size() ; i++) ht[t[i]]++;
for (int i = 0 , j =0,cnts = 0; j < s.size();j++){
hs[s[j]]++;
if(hs[s[j]] <= ht[s[j]]) { cnts++;}
while (hs[s[i]] > ht[s[i]]){
hs[s[i]]--;i++;
}
if(cnts == t.size() ){
if (ans.empty() || ans.length() > j-i+1){
ans = s.substr(i, j-i+1);
}
}
}
return ans;
}
};
没懂之处:第15行,为什么是等于呢?(个人理解,大于等于应该也是合适的,结果显示是合理的。但是原作者,只是书写了等于,不明所以)