开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情
[769. 最多能完成排序的块]
题目的含义可以认为是:可以将数组划分为不同的子数组,然后每个子数组单独进行排序, 最后得到的排序数组的顺序要和对整个数组整体排序的结果一样! 要求的是最多可以把数组划分为多少个子数组! (最多能划分多少块)
很典型的贪心!
长度为n, 因为数组的范围是0~n-1, 这时我们发现排序后的数组它每个元素的值与它的下标值是一致的 当我们遍历到第i个位置的时候:
- 如果当前i位置可以被单独切分为1块, 那么前i个位置的最大值一定是i下标, 此时i位置才能被划分为一个块
- 要不然的话:一定有比i小的元素划分到后面的块, 这样的话,对所有块排序之后,一定不满足升序
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int ans = 0;//记录能划分成多少个块
int maxVal = 0;//记录当前0~i位置的最大元素
for(int i = 0;i<arr.size();i++)
{
maxVal = max(arr[i],maxVal);//前i个位置的最大元素
if(maxVal == i) //当前i是0~i位置的最大元素,可以划分为单独的一个块!
ans++;
}
return ans;
}
};
[904. 水果成篮]
题目含义:找至多包含两种元素的最长子串,(求只包含两种元素的最长连续子序列)返回其长度
做法:滑动窗口:
定义一个哈希表记录当前果树种类及其对应的个数, 定义一个变量valid记录当前窗口的水果种类数,维护一个滑动窗口,不断扩展右边界,记录当前装入的水果种类和数量, 一旦水果种类超过2,就收缩左边界,移除左边界的水果,直到水果种类<=2, 然后统计当前最长子串
- 遍历数组,假设当前i位置的水果为fruit, 先判断当前水果是否出现过 : map[fruit] == 0说明当前水果在[left,right]范围没有出现过,是新增的水果,valid++ 然后哈希表中增加当前水果的出现次数
- 然后考察当前窗口内的水果,如果果树种类>2,从窗口左边弹出果树,直到满足规则:当前[left,right]水果种类<=2
- 然后记录当前的最长子串
class Solution {
public:
//维护一个滑动窗口,不断扩展右边界,记录当前装入的水果种类和数量
//一旦水果种类超过2,就收缩左边界,移除左边界的水果,直到水果种类<=2
//题目含义:找至多包含两种元素的最长子串,(求只包含两种元素的最长连续子序列)返回其长度
int totalFruit(vector<int>& fruits) {
unordered_map<int,int> map;//果树种类-个数
int n = fruits.size();
int valid = 0;//记录当前窗口的水果种类数
int left = 0,right = 0;
int res = 0;//记录最长的子串长度
for(right = 0;right<n;right++)
{
int fruit = fruits[right];//当前窗口新加入的水果
if(map[fruit] == 0)//说明当前水果没有出现过,是新增的
{
valid++;
}
map[fruit]++;//水果对应出现次数++
//考察当前窗口内的水果,看是否满足规则
//如果果树种类>2,从窗口左边弹出果树,直到满足果树种类<=2
while(valid>2)
{
//弹出当前窗口左边的果树->即left往后走,次数--
int fruit = fruits[left]; //当前左边对应的水果
left++;
map[fruit]--;//出现次数--
if(map[fruit] == 0) //该水果没有了,种类-1
valid--;
}
//此时[left,right]的水果就是满足规则的,长度为:right-left+1
res = max(res,right-left+1);
}
return res;
}
};