解法
代码一:按块扫描+滑动窗口
手动模拟一下感觉不难,自己写代码感觉总有很多琐碎的细节
一开始按块扫描为了思路简单,但是按照代码二也不难
class Solution {
public:
int totalFruit(vector<int>& fruits) {
if(fruits.size() == 0) return 0;
int bucket[2] = {0,0};
int cnt[100005]={0}, type[100005]={0}, last=0, idx=0;
type[0] = fruits[0];
// type用来表示水果类型,cnt用来表示该种水果的数量, 最后数组长度为idx
// 按块扫描,表示成(type[i], cnt[i])的形式
for(int i=0; i<fruits.size(); i++){
if(fruits[i] == fruits[last]) {
cnt[idx]++;
}
else{
cnt[++idx]++;
type[idx] = fruits[i];
last = i;
}
}
// idx==0说明只有一种水果
if(idx == 0) return cnt[0];
int collect = cnt[0]+cnt[1], ans=collect;
bucket[0] = type[0];
bucket[1] = type[1];
// bucket是一个大小为2的滑动窗口,注意是有序的,
for(int i=2; i<=idx; i++){
// 当前水果同bucket[0]的相同,可以累加,需保证bucket内部有序
if(type[i] == bucket[0]){
bucket[0] = bucket[1];
bucket[1] = type[i];
collect += cnt[i];
ans = max(collect, ans);
}
// 当前水果同bucket[0]的不同,需丢掉bucket[0]类型的水果
// eg:fruits=[0,1,0,1,2], type=[0,1,0,1,2], cnt=[1,1,1,1,1], 当前i=4,bucket=[0,1]
// 需要将水果0丢掉,此时留下来的水果数量为cnt[i-1](这个要想明白)
else{
collect = cnt[i-1];
bucket[0] = bucket[1];
bucket[1] = type[i];
collect += cnt[i];
ans = max(collect, ans);
}
}
return ans;
}
};
代码二:直接滑动窗口,不要按块扫描
实际上没必要先扫描一遍,滑动窗口从左边开始消除的时候,每消除一个,就判断当前水果种类数量,比如[0,1,0,1,2],消除第一个0后水果0并没有都丢掉,因为窗口大小为2,如果当前窗口中含有水果2,则之前的水果只能是水果1,好像从水果2从右往左添加连续的水果1也行。
class Solution {
public:
int totalFruit(vector<int>& tree) {
unordered_map<int, int> bucket;// 建立水果类型到数量的对应
int ans = 0, cnt = 0, left = 0;
for (int i = 0; i < tree.size(); i++) {
bucket[tree[i]]++;
cnt++;
// 开始从滑动窗口左边消除, bucket.size()为水果种类数量,eg:[0,1,0,1,2]
while (bucket.size() > 2) {
bucket[tree[left]]--;
// 该中类型的水果丢完了
if (bucket[tree[left]] == 0) bucket.erase(tree[left]);
left++;
cnt--;
}
ans = max(ans, cnt);
}
return ans;
}
};