Leedcode刷题——滑动窗口

应用场景

一般用于求一个序列中符合条件的最大(小)子序列
如:
①T209长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。

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

示例 1:

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

输入:target = 4, nums = [1,4,4]
输出:1
示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

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

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

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

示例 1:

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

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

用以上两个题目来阐述思想

暴力方法

思路:i起始位置,对于每一i,j遍历后序元素,寻找符合要求的所有情况,并找出最大(小)子集
时间复杂度:O(n^2)

滑动窗口

总体思路:用i和j维护一个满足目标条件的连续序列,i指向起始位置,j指向结束位置
变量设置
i——子序列的起始位置
j——子序列的最终位置
result——记录符合要求的最大(小)长度
length——当前长度
伪代码

int i = 0;
//j不断后移,讨论在每个j下i的可能性
for(j = 0; j < 总长度; j++){
	if(i到j的序列符合条件) {
		更新子序列长度
		判断是否要更新result;
		//更新i;
	}
	else if(不符合条件){
		//更新i;
		更新子序列长度
	}
}

几个问题
①符合条件是什么条件?
②更新i的时机?
③怎么更新?即i怎么向前进,丢掉哪些元素

例1:T209长度最小的子数组
符合条件是什么条件?当前子序列的和>=要求

if(sum >= target)

更新i的时机:当找到一个序列满足要求时,需要将i向后移,看看有没有满足要求的更短的序列
即更新时机为

if(sum >= target)

怎么更新:假设i向前移动后,子序列仍然满足要求,则更新i
即:

//如果总和复合要求,更新i
while(sum >= target){
                sum -= nums[i];
                i++;
            }

例2:T904水果成篮
符合条件是什么条件?(什么时候窗口可以持续增长=>什么时候可以往篮子里继续放水果)
即:
①一个/两个篮子为空
②篮子里的类型就是遇到的新果树的类型

fruit[j]表示遇到的新果树的类型, 
type1、type2表示篮子里的类型,初始化为-1,表示篮子为空
//篮子里的类型就是遇到的新果树的类型
 if(fruits[j] == type1 || fruits[j] == type2)
//一个/两个篮子为空
 else if(type1 == -1)
 else if(type2 == -1)

更新i的时机:出现了新的水果种类的时候需要更新i
即:

else (不符合条件)

怎么更新:更新到子序列中只有两种水果为止
即:

设置type1和type2分别保存篮子中两种类型的水果
//保留和新j相邻的元素
int tmp = type1和type2中不和j相邻的类型;
/*
如[1,2,1,2,3], type1 = 1, type2=2
j = 指向3时,1和3不相邻,tmp=1
*/
//index从后往前找到tmp最后一个出现的位置并更新i
int index = j - 1;
while(fruits[index] != tmp) index--;
i = index+1;

剩下的套模板就好了

T209、T904代码

①T209长度最小的子数组

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int i = 0;
        int result = INT32_MAX;
        int sum = 0;
        for(int j = 0; j< nums.size(); j++){
        	//更新子序列长度
            sum = sum + nums[j];
            //如果符合要求
            while(sum >= target){
            	// j - i + 1为新的长度,如果新长度小于记录,更新记录
                result = j - i + 1 < result ? j - i + 1 : result;
                //更新i,更新子序列长度
                sum -= nums[i];
                i++;
            }
        }
        //有记录则返回记录,没有记录返回0
        return result <= nums.size() ? result:0;
    }
};

②T904水果成篮

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int type1 = -1, type2 = -1;//记录篮子里的两种类型
        int length = 0;//子序列长度
        int i = 0;//子序列的起始位置
        int maxlength = 0;//最大长度
        for(int j = 0; j< fruits.size(); j++){
        	//符合条件情况1
            if(fruits[j] == type1 || fruits[j] == type2){
            	//更新子序列长度
                length++;
                //如果长度大于记录,更新记录
                if(length > maxlength) maxlength = length;
            }
            //符合条件情况2
            else if(type1 == -1){
                type1 = fruits[j];
                //更新子序列长度
                length ++;
                //如果长度大于记录,更新记录
                if(length > maxlength) maxlength = length;
            }
            else if(type2 == -1){
                type2 = fruits[j];
                //更新子序列长度
                length++;
                //如果长度大于记录,更新记录
                if(length > maxlength) maxlength = length;
            }
            //不符合条件的情况
            else{
                //tmp记录和fruits[j]不相邻的元素
                int tmp;
                fruits[j-1] == type1 ? (tmp = type2 , type2 = fruits[j]) : (tmp = type1, type1 = fruits[j]);

                //从fruits[j]开始往前找到tmp最后一个出现的位置,更新i
                int index = j - 1;
                while(fruits[index] != tmp) index--;
                i = index+1;
				
				//更新子序列长度
                length  = j - i + 1;
                //这种情况长度一定是减少的,不需要更新maxlength
            }
        }
        return maxlength;
    }
};

你可能感兴趣的:(刷题,算法,数据结构,c++)