题目
思路
题目要求要通过分块的排序来使整个数组变成升序排列,第一时间想到就是如果后面的数比前面的数小那么就要分成一块,于是急速完成以下代码
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int ans = 0;
for (int i = 0; i < arr.size(); i++) {
int flag = i;
for (int j = i; j < arr.size(); j ++) {
if (arr[i] > arr[j]) {
flag = j;
}
}
i = flag;
ans ++;
}
return ans;
}
};
样例通关,提交
对了大半,但从这个错误样例中看出,思路有个严重的漏洞,我们的程序将数组分成了[1,4,0],[2],[3],[5]四块,这明显是错误的,因为第一块中有4,那么后面的2,3也应该包含在里面才对。
方向上似乎想得太简单,于是换一种思路。因为是升序排列,所以第一个块中一定有0。于是可以先找到0所在的位置,如果数组开头到0这个位置能排序后数之间的间隔都为1,那么这就是第一块,如果不能那就继续往后找,直到条件达成。
那怎么达成这样的逻辑呢?可以发现n最大只有10,是很小的数,可以借鉴昨天桶的思想,把数组装进一个桶里面,不过和昨天不同,今天需要一边装一边处理。遍历数组,将经过的数放进桶里面,直到找到0,然后从大到小看看桶里装了什么,如果桶里面最大的到0都存在那么这就是一个我们需要的块,如果不是那就继续往后放,直到条件达成。就像下图,两种情况下,第一次找到块时桶的状态
nums = [1,0,4,2,3,5,6,7]
busket = [1,1,0,0,0,0,0,0]
nums = [1,4,0,2,3,5,6,7]
busket = [1,1,1,1,1,0,0,0]
找到第一个块以后,之后就是将剩下的部分当成一个整体,重复上述过程就可以达到答案,于是代码如下
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int busket[11] = {0};
int ans = 0;
int flag = 0;
for (int i = 0; i < arr.size(); i ++) {
busket[arr[i]] = 1;
if (busket[flag]) {
for (int j = 10; j >= flag; j --) {
if(busket[j]) {
int cur = j;
while(busket[cur]&&cur>flag) cur --;
if (cur == flag) {
ans ++;
flag = j;
}
break;
}
}
}
}
return ans;
}
};
然后提交,通过,但是这种方法明显的时间复杂度超标,达到了O(),不过因为数比较小很难看出效率上的差别,再让我们看看评论有什么更好的方法
最后看到了一种更好的思路,因为是结果是升序排列且数不重复,所以当[0, i]的和与他们下标的和相等时,就可以切出第一个块,后面同理。于是代码如下
class Solution {
public:
int maxChunksToSorted(vector<int>& arr) {
int ans = 0;
int sumArr = 0;
int sumIndex = 0;
for (int i = 0; i < arr.size(); i ++) {
sumArr += arr[i];
sumIndex += i;
if (sumArr == sumIndex) ans ++;
}
return ans;
}
};
代码简单高效,时间复杂度为O(n),空间复杂度为O(1),结果也十分优秀
其他优秀的思路也很多,可以说这题的解法五花八门,如果感兴趣可以多看看评论区大佬们。
反思
今天的题目总体上不难,而且数据也比较小,可以从很多方向上去思考,从而得出更多的解法。