C++滑动窗口例题

LeedCode 209

长度最小的子数组

题目:给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

--》我的想法:

当时我对滑动窗口的“滑动”二字理解并不深刻,仅仅以为“滑动”不过是两个指针控制一个窗口的初末位置。当时我写的伪代码:

if(sum < target) j++;//窗口右边++
else if(sum >= target) i++;//窗口左边++

当时想的就是想办法循环上面的两行代码,并把sum想办法更新就完事了(sum是窗口中数字的和,即\sum_{nums[i]}^{nums[j]}

--》滑动窗口:

怎么理解“滑动”呢?写完本题之后,sum其实不需要更新多次,比如i++之后,按我之前的想法还需要重新算一遍sum,但是完全可以用sum -= nums[i]来代替,这样就不需要重新计算sum。归根结底,这样遍历完整个数组,对于sum:相当于只完完全全的计算了一遍sum,而对于元素:每个元素只有出窗口和入窗口的时候用到了,所以时间复杂度是O(2n)=O(n)。【后续可能会有新的理解】

 

代码:

for(int j=0;j<nums.size();j++)
{
sum += nums[j];//j是右边
while(sum >= target)
{
    result = min(result,j-i+1);//用min的时候要加上#include <algorithm>
    sum -= nums[i++];
}
return result == INT32_MAX ? 0:result;

加个完整代码:

#include<bits/stdc++.h>
using namespace std;
int minSubArrayLen(int target, vector<int>& nums) {
    int sum =0;
    int result = INT32_MAX;
    int i=0;

    for(int j=0;j<nums.size();j++)
    {
    sum += nums[j];//j是右边
    while(sum >= target)
    {
        result = min(result,j-i+1);//用min的时候要加上#include <algorithm>
        sum -= nums[i++];
    }
}
    return result == INT32_MAX ? 0:result;

}

int main()
{
    vector <int> nums = {2,3,1,2,4,3};
    cout<<minSubArrayLen(7,nums);
    return 0;
}
  •  LeedCode 3

3. 无重复字符的最长子串

题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

滑动窗口只是一个思想,想要会写代码,还得具备牢固的C++知识,为了写这一题,又去看了map,unordered_map,set,unordered_set。学完基础知识之后,发现利用封装好的函数去解这题也不算难。

下面附上代码:

#include <bits/stdc++.h>
using namespace std;

int lengthOfLongestSubstring(string s) {
    if(s.size() == 0) return 0;
    set<char> lookup;
    int maxStr = 0;
    int left = 0;
    for(int i = 0; i < s.size(); i++){
        while (lookup.find(s[i]) != lookup.end()){
            lookup.erase(s[left]);
            left ++;
        }
        maxStr = max(maxStr,i-left+1);
        lookup.insert(s[i]);
}

    return maxStr;
    
}
int main()
{
    string s = "abcabcbb";
    cout<<lengthOfLongestSubstring(s);
    return 0;
}
  • LeedCode 904

904. 水果成篮

说白了就是①找遍历所有窗口,②剔除掉不合题意的窗口,③然后从剩下的窗口中,找到长度最大的。

本题中的不合题意是指:窗口内元素种类数目大于2;所以遍历所有窗口的时候要剔除掉这种窗口

方法:哈希表+滑动窗口

int totalFruit(vector<int>& fruits) {
map <int,int> mymap;
int left = 0;//窗口左边
int win_size = 0;//窗口长为0
//1、遍历所有窗口
for(int i = 0;i<fruits.size();i++)
{
    mymap[fruits[i]]++;/*这一行将fruits[i]这个元素加入到mymap中,只要i++之后就一定会执行这句话,所以这句话放到了while循环之外。*/
    //2、(相当于)剔除种类数大于2的窗口
    while(mymap.size()>2) 
    {
        mymap[fruits[left]]--;
        if(mymap[fruits[left]]==0) mymap.erase(fruits[left]);
        left++;
    }
    //3、找到窗长最大的
    win_size = max(win_size,i-left+1);
}
return win_size;
}

参考链接:代码随想录 (programmercarl.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值