LeetCode 768. 最多能完成排序的块 II

99 阅读3分钟

LeetCode 768. 最多能完成排序的块 II

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

一、题目描述

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

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

我们最多能将数组分成多少块? 示例 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] 可以得到最多的块数。

二、解题思路

首先需要考虑如何划分每个区间才能使得区间的排序之后和整个数组排序的结果相等。

那么就可以得出一个结论:对于每组数据他的的最大值一定小于下一组的最小值,那么久可以使用单调栈。

思路

初始为空数据直接入栈,当遇到比当前栈顶大的,我们就进行入栈

why: 遇到比栈顶大的说明可能是下组数据的最小值。也只是可能,后面可能有更小的!

如果后面遇到更小的说明之前的数据也要划分到和这个小的数据一组

how: 首先栈顶一定是当前组最大的数据,把最大值拿出来,之后把所有比当前值大的数据出栈,那么前面也就是比当前数据小的,这样排序的结果不会出现比当前更小的。

图示

情况一

  1. 当数据入栈后,后面的数据比他小的都会自动归为一组,如图第一步和第二步
  2. 当前数据比之前入栈的大,就会自动归为下一组,当前后面可能会有更小的那么就要重新划分
  3. 后面的两个数组都比之前的数据大,直接入栈

情况二

对比情况一,发现在第四步的时候发现了更小的数据,要把这个最小的数据排到对应的位置,之前分组就要进行合并,至于合并几组数据就要取决之前的数据那个比这个数据小,就找到当前数据的位置

三、编码

var maxChunksToSorted = function (arr) {
    let stack = []
    // 找到某一区域最大的,如果遇到更大的就划分一个新的区域
    for (let i = 0; i < arr.length; i++) {
        // 最大值直接放进去,对应情况一
        if (stack.length === 0 || stack[stack.length - 1] <= arr[i]) {
            stack.push(arr[i])
        } else {
            // 比之前的数据小,取出栈顶最大的,之前的数据依此和当前数据比较,找到比当前值小,这个位置就是当前值的位置,对应情况二
            const mx = stack.pop();
            while (stack.length && stack[stack.length - 1] > num) {
                stack.pop();
            }
            stack.push(mx);
        }
    }
    return stack.length;
};

欢迎点赞,关注,收藏