06、限定条件下的移动窗口
前提:
对于一般下的移动窗口问题,就是给定一个定义好的长度target, 然后再子数组找到最小长度满足里面的元素之和是大于target就可以了。
但是对于限定条件的移动窗口问题,就需要改变策略了,例如:
题目:
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- 你只有两个篮子,并且每个篮子只能装单一类型的水果。每个篮子能够装的水果总量没有限制。
- 你可以选择任意一棵树开始采摘,你必须从每棵树(包括开始采摘的树)上恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
简化这个题目:再一个数组fruits中,fruits[i]表示的是在第i 棵树上的水果类型,这个类型是用数字来表示的,现在有两个篮子,一个篮子装一个类型的水果,一个树只能采摘一次水果,然后往后面开始采摘,求可以找到的最大子数组长度
源代码:
class Solution{
public:
int totalFruit(vector<int> &fruits){
const int MAX = 100001; // 定义最大数
int i = 0; // 定义起始位置
int kind = 0; // 定义种类数,不可以大于2
int result = 0; // 需要返回的数
vector<int> freq (MAX,0); // 一个用来存储当前窗口种类的数量,下标表示种类,其对应的为数量
for (int j = 0 ; j <fruits.size() ; j++){ // j 负责窗口的终止位置
int fruit = fruits[j];
freq[fruit] ++; // 开始统计种类fruit对应的数量
if (freq[fruit] == 1){
// 开始判断是否有数量,如果有就将kind ++;
kind ++;
}
while (kind > 2){
int leftfruit = fruit[i]; //如果种类超过了2就要将 i 前移,但是你得把存放数量的置零
// 下面的部分就是移动窗口的精髓了,移动左边起始位置
freq[leftfruit] --;
if (freq[leftfruit] == 0) kind --;
i ++;
}
// OK呀,到了这一步就要开始统计长度了
int subLength = j - i + 1;
result = result > subLength ? result : subLength;
}
return result;
}
};
注:
- 这道题多了一个判定条件就是要求kind > 2,但是本质还是一样的
- 新增一个数组,用来存放类型的数量
- 在kind ++ 的时候,判定条件是freq[leftfruit] == 1 ,因为开始时候的数组都是0,只要等于1了就说明有了新的类型,才加1,为而不是其他的条件,执行kind ++才保证执行了一次
- freq[leftfruit] == 0时候 kind -- ,也同样避免了kind在变化的时候freq中的数量还没有变为0
- freq是用来存放当前窗口的类型数量,所以本质上也是一个移动的存储器

浙公网安备 33010602011771号