一般用于求一个序列中符合条件的最大(小)子序列
如:
①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长度最小的子数组
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;
}
};