携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 20 天,点击查看活动详情
题目描述
给定一个数组arr,要求按照要求分割数组,返回数组能分割成的最大子数组的数目。
要求:将arr分割成若干子数组,对每个子数组进行排序后再将各个子数组进行合并,所得的数组与原数组排序后的顺序相同。
例1:输入:arr=[1,1,0,0,1] 输出:2
解释:可以将arr拆分为[1,1,0,0]、[1],子数组排序后结果为[0,0,1,1]、[1],合并后结果为[0,0,1,1,1]满足与原数组排序后结果相同的要求。
例2:输入:arr=[1,1,1,0,1,0,0,0,1,0] 输出:1
解释:排序后结果应为[0,0,0,0,0,1,1,1,1,1]。所以最多把原数组作为子数组才能满足要求。
原题地址:768. 最多能完成排序的块 II
解题思路
本题与昨天发的769. 最多能完成排序的块相似,但是本题中元素是可以重复的。
首先应该找到数组排序后各元素所在的位置,即对数组进行排序存储到vec中,方便后面进行比较。用vec1来维护从后到前的最小值,用来寻找在当前位置之后所有比当前位置之前最大值小的索引。例如例1中vec1为[0,0,0,0,1],当维护到索引0的位置时,最大值为1,所以可以用vec1来找到比最大值1小的所有节点,可直接寻找到arr的索引3,而对数组进行排序后索引3的位置为1,等于当前维护的最大值1.所以[1,1,0,0]可以划分为一个子数组。
实现代码
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int n = arr.size();
// 存储排序后的数组、存储arr从后往前的最小值
vector<int> vec = arr,vec1 = arr;
// 维护arr从后往前的最小值
for(int i=n-2; i>=0; i--) vec1[i] = min(vec1[i+1],vec[i]);
// 记录结果、最大值
int re s= 0,ma = arr[0];
// 排序数组,维护元素应该所属的位置
sort(vec.begin(),vec.end());
for(int i=0; i<n; i++){
ma = max(ma,arr[i]);
// 寻找当前索引后面所有比当前最大值小的元素
while(i<n-1 && vec1[i+1]<ma){
ma = max(ma,arr[i]);
i++;
}
// 如果当前位置排序后所属的元素与最大值相同,则可以划分出一个子数组
if(ma == vec[i]) res++;
}
return res;
}
};