LeetCode:768. 最多能完成排序的块II (困难)

题目描述

这个问题和“最多能完成排序的块”相似,但给定数组中的元素可以重复,输入数组最大长度为2000,其中的元素最大为108

arr是一个可能包含重复元素的整数数组,我们将这个数组分割成几个“块”,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。

我们最多能将数组分成多少块?

示例 1:
输入: arr = [5,4,3,2,1]
输出: 1
解释:
将数组分成2块或者更多块,都无法得到所需的结果。
例如,分成 [5, 4], [3, 2, 1] 的结果是 [4, 5, 1, 2, 3],这不是有序的数组。
示例 2:
输入: arr = [2,1,3,4,4]
输出: 4
解释:
我们可以把它分成两块,例如 [2, 1], [3, 4, 4]。
然而,分成 [2, 1], [3], [4], [4] 可以得到最多的块数。

题解

题解1:辅助栈

找到可以完成排序的块,实际上就是在找局部最大值,且局部最大值按升序顺序排列。

局部最大值有多少个,则可以完成排序的块就有多少个,每个局部最大值对应一个块。

使用辅助栈对局部最大值进行统计。

  • 首先将数组首元素当作第一个最大值,入栈;
  • 若当前值大于等于栈顶元素,则将当前值入栈,相当于增加了一个局部最大值;
  • 若当前值小于栈顶元素(说明需要将此元素合并到前一个块中,也就是需要减少栈内的局部最大值,)首先保存最大的栈顶元素,之后弹出,继续对比栈内元素,若小于栈内元素,继续弹出,直到当前值大于等于栈顶元素,或栈为空,此时将保存的最大值进栈,合并完成。

最终块的个数即为局部最大值的个数。

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        stack<int> stk;
        for(int i = 0; i < arr.size(); ++i){
            if(stk.empty() || arr[i] >= stk.top()) stk.push(arr[i]);
            else{
                int head = stk.top();//排序块的最大值
                stk.pop();
                //需要和前面的排序块合并
                while(!stk.empty() && arr[i] < stk.top()) stk.pop();
                stk.push(head);//插入排序块的最大值
            }
        }
        return stk.size();
    }
};

复杂度分析
时间复杂度: O(N),其中 N 为数组长度。
空间复杂度: O(N)。

题解2:求和法

参考: 768. 最多能完成排序的块 II【滑动窗口、单调栈、JavaScript】
原数组进行分块后,每一个分块排序后和排序后的数组中对应的数字是一样的,因此它们的和也是一样的了。我们可以用一个滑动窗口同时扫描原数组和排序数组,当窗口中数字的和一样时,就将数组进行分块。

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        vector<int> sorted_arr = arr;
        int size = arr.size();
        sort(sorted_arr.begin(),sorted_arr.end());
        int count = 0;
        long int sum1 = 0;
        long int sum2 = 0;
        for(int i = 0; i < size; i++){
            cout << "sorted_arr[ " << i << "] ="<< sorted_arr[i] << endl;
            sum1 += arr[i];
            sum2 += sorted_arr[i];
            if(sum1 == sum2){
                count++;
            }
        }
        return count;

    }
};

复杂度分析

  • 时间复杂度:O(NlogN),N 为数组长度,数组排序时间认为是 NlogN,滑动窗口遍历数组时间为 N。
  • 空间复杂度:O(N),N 为数组长度。

参考

最多能完成排序的块 II (辅助栈法,清晰图解)
768. 最多能完成排序的块 II 滑动窗口、单调栈、JavaScript
C++ 左右遍历极小极大
C++,利用栈,栈头保留当前排序块的最大值
单调栈——最多能完成排序的块2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值