一些关于滑动窗口的简单实现

滑动窗口

题目一:

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

  • 输入:s = 7, nums = [2,3,1,2,4,3]
  • 输出:2
  • 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

提示:

  • 1 <= target <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

解法一:暴力解法

int minSubArrayLen(int target, int* nums, int numsSize) {
    int i,j,sum=0,count=0,n=0;

	int len=INT_MAX; //设置len为最大值,用于检验是否被赋值
	for(i=0;i<numsSize;i++){
		sum=0;
		for(j=i;j<numsSize;j++){
			sum+=nums[j];
			if(sum>=target)//发现更小的len则更新长度
            {
				count=j-i+1;//子序列的长度
				len=count>len?len:count;
				break; 
			}
		}
	}
	return len == INT32_MAX ? 0 : len;
}
  • 时间复杂度 O(n^2)
  • 空间复杂度 O(1)

解法二:滑动窗口

基本概念

滑动窗口是一种基于双指针的思想,想过两个指针指向的元素之间形成的一个窗口。就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。

分类

窗口共分为两类,一是固定大小的窗口,二是大小动态变化的窗口。

应用情景

1.数据结构为数组和字符串

2.求某一个子串或者子序列最长最短等问题/求某一个目标值

3.该题目可通过暴力破解

滑动窗口的优点

可显著减少操作次数,减少时间复杂度

思路

用两个指针一个代表起始位置和终止位置,终止位置的指针的指向不断向后移动,判断其是否大于等等于s,若大于等于s,终止位置的指针不动,起始位置的指针向前移动,再次判断是否大于等于s,当不满足大于等于s的条件,将上一个起止的长度存储进length中。

用给出的样例为例子,我们来简单模拟滑动窗口的运行过程

1.初始时,用两个指针一个代表起始位置和终止位置,窗口为[开始,终止),左闭右开。
在这里插入图片描述

2.用代表终止位置的指针遍历数组,找到满足大于等于s的子数组,形成窗口

在这里插入图片描述

3.起点开始向后移动,再进行判断大小,更新窗口的数据

在这里插入图片描述

4.若符合条件则起点继续向右移动,直到不满足题目条件,将符合子数组长度储存进入length

在这里插入图片描述

5.当不满足题目条件,起始指针停止后,终止指针继续向右移动,返回进行第二步
在这里插入图片描述

6.最后直到找到符合题目条件的最短子数组

在这里插入图片描述

代码实现
int minSubArrayLen(int target, int* nums, int numsSize) {
   int i,j=0,sum=0,result=INT_MAX,len;
   for(i=0;i<numsSize;i++)//终止位置前移
   {
       sum+=nums[i];//找到大于等于的s数组
       while(sum>=target){
           len=i-j+1;//求出数组长度
           result=result>len?len:result;
           sum-=nums[j];
           j++;//起始位置前移
       }
       
   }
   return result == INT_MAX ? 0 : result;//最终返回输出结果
}

题目二:

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

提示:

  • 1 <= fruits.length <= 105

  • 0 <= fruits[i] < fruits.length

    解法思路:

    题意:找出数组中个数最多,由两个数字组成的连续子数组

    1.设置一左一右两个指针,right表示采摘到了那一棵树确定,left表示将两篮中的一篮水果清空的位置,双指针

    2.确定左右指针的位置之后,开始用while循环清点果篮中水果的个数,与max比较,符合条件后存入max

    3.将一个果篮清空,找到下一个符合条件的连续子数组,直至最后一棵果树

代码实现

int totalFruit(int* fruits, int fruitsSize) {
    int left=0,right=0;
    int count=0;
    int a[100000]={0};
    int max=0;
    while(right<fruitsSize){
        if(a[fruits[right]]==0)//计算水果种类,找到新水果
        {
            count++;
        }
        a[fruits[right]]++;//水果种类加一
        while(count>2)//当水果种类超出两种,进入循环缩小窗口
        {
            a[fruits[left]]--;//缩小窗口,将先前两个篮子中的一个清空
            if(a[fruits[left]]==0){
                count--;
            }
            left++;//统计水果的数量
        }
        max = (right - left + 1) > max ? (right - left + 1) : max;//比较得到最大值
        right++;//指针right向右移动
    }
    return max;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值