【每日一题】769.最多能完成排序的块 2022/10/13

题目

最多能完成排序的块

思路

题目要求要通过分块的排序来使整个数组变成升序排列,第一时间想到就是如果后面的数比前面的数小那么就要分成一块,于是急速完成以下代码

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(n^{2}),不过因为数比较小很难看出效率上的差别,再让我们看看评论有什么更好的方法

 最后看到了一种更好的思路,因为是结果是升序排列且数不重复,所以当[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),结果也十分优秀

 其他优秀的思路也很多,可以说这题的解法五花八门,如果感兴趣可以多看看评论区大佬们。

反思

今天的题目总体上不难,而且数据也比较小,可以从很多方向上去思考,从而得出更多的解法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今夜大疯小宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值