【刷题日记】768. 最多能完成排序的块 II

简介: 【刷题日记】768. 最多能完成排序的块 II

本次刷题日记的第 92 篇,力扣题为:768. 最多能完成排序的块 II

一、题目描述:

继续干最多能完成排序的快 II , 看看进阶版的是什么样的需求

image.png

二、这道题考察了什么思想?你的思路是什么?

进阶版的最多能完成排序的块 II , 是够会促使我们改变上次做题的方式和思路呢

这一次的题目变动情况是这样的:

  • 题目中的数组长度最大限度变成了 2000,数组中的数据最大元素变成 10^8,再也不是 0 到 n-1 了
  • 题目给出的 arr 数组中的元素,并不是根据 arr 长度来的了,数组里面的元素数值不可预测,只知道是最大为 10^8
  • 要求我们还是继续拆分数组,拆分成最大的块,并且将这些块,各自排序,拼接成升序之后的原数组

分析

根据本次进阶的排序块问题,我们也许不能直接用 arr 的数组索引来做文章了,因为 arr 里面的元素索引和具体对应的数值已经没有啥直接关系了,既然继续沿用索引的方式行不通,那么我们从其他方面找解决方式

咱们思考的方向可以是这样的:

  • 第一,无论拆分成多少块,各自排序拼接之后,都需要是和原数组升序之后的结果一致
  • 第二,无论如何拆分块以及其各自排序,对于数组中的数据,我们是一点也不能去修改的,原来有多少个 1 ,那么拆分数组后,总的来说,还是多少个 1

这个时候,既然我们其实还是需要和原数组的升序结果做对比的话,再加上我们不能使用索引做文章,那么我们是否可以使用每个块的数字出现频次做文章呢?

例如我们可以看到示例 2 中

Arr = [2, 1, 3, 4, 4]

原数组 2 1 3 4 4
升序后 1 2 3 4 4

这个时候,除了眼睛可以一眼看出可以最多拆分多少块外,我们还需要有明确的程序和逻辑

我们其实可以看到 ,咱们是可以拆分成 4 个块的,再仔细看每一个块的原数组内容和排序后的数据内容

image.png

实际上我们是可以看出,对于原数组中一个单独的块中,当前块中的数字个数,类型,出现的频次,与升序后的原数组对应的块中的 数字个数,类型,出现的频次 完全一致,只是出现快中的索引位置不一样而已,这也是为什么最开始我就说到,咱们就不要打索引的注意了

那么,这个时候咱们做题分析的话,

  • 第一,需要一个对原数组升序之后的结果来进行帮助比较和计算,定义数组为 help
  • 第二,需要一个 map 来记录某一个块中,原数组出现过就 +1,help 数组也出现过就 -1,对于 map 来说,一加一减就还原了,那么遍历原数组 arr 过程中,如果有出现咱们比较数字频次之后,map 仍然长度为 0,则咱们就需要拆分块了
  • 例如上述案例,遍历到arr的第二个元素的时候,出现的 2,1 与 排序数组的前两个元素 1,2 出现的频次一样,这个时候,就进行拆分块

至此,剩下就是按照上述思路进行撸代码吧

三、编码

根据上述逻辑和分析,我们就可以翻译成如下代码

  • 需要关注,咱们需要先对 arr 数组进行排序,得到 help
  • 遍历 arr,使用 cntMap 来标记在遍历过程数字出现的频次,arr 中出现就 +1,相应的 help 中出现就 -1,逻辑处理完毕后,校验 cntMap 长度是否为 0,若是,这满足我们拆分的条件,则拆分即可
  • 最终返回最大拆分的次数

编码如下:

func maxChunksToSorted(arr []int) int {
    cntMap := map[int]int{}
    help := append([]int{}, arr...)
    sort.Ints(help)
    var res int
    for index, aNum := range arr {
        // 表示 aNum 在 arr 中出现频次+1
        cntMap[aNum]++
        if cntMap[aNum] == 0{
            delete(cntMap, aNum)
        }
        // 在来看 help 中对一个位置数值的频次
        cntMap[help[index]]--
        if cntMap[help[index]] == 0 {
            delete(cntMap, help[index])
        }
        // 最后校验我们的 map 中没有数据,说明目前为止,遍历的数据的频次 arr 和 help 对应数据的频次一致
        if len(cntMap) == 0 {
            res++
        }
    }
    return res
}

四、总结:

image.png

本题的处理方式使用了 golang 自带库中的快速排序,因而时间复杂度是 O(nlogn) ,空间复杂度比较明确,我们开辟了一个 help 切片,数据长度和题目给出的 arr 一样,则为 空间复杂度为O(n)

原题地址:768. 最多能完成排序的块 II


欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image.png

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

相关文章
LeetCode题解-让所有学生保持开心的分组方法数
LeetCode题解-让所有学生保持开心的分组方法数
|
存储 Cloud Native
【刷题日记】871. 最低加油次数
本次刷题日记的第 78 篇,力扣题为:871. 最低加油次数,困难
|
算法 索引 Cloud Native
【刷题日记】769. 最多能完成排序的块
【刷题日记】769. 最多能完成排序的块
|
索引 Cloud Native
【刷题日记】954. 二倍数对数组
本次刷题日记的第 21 篇,力扣题为:954. 二倍数对数组 ,中等
|
测试技术 Cloud Native
【刷题日记】532. 数组中的 k-diff 数对
本次刷题日记的第 67 篇,力扣题为:532. 数组中的 k-diff 数对,中等
|
存储 Cloud Native
【刷题日记】128. 最长连续序列
本次刷题日记的第 56 篇,力扣题为:128. 最长连续序列,中等
|
搜索推荐 Cloud Native
【刷题日记】1403. 非递增顺序的最小子序列
【刷题日记】1403. 非递增顺序的最小子序列
|
Cloud Native
【刷题日记】73. 矩阵置零
【刷题日记】73. 矩阵置零
C/C++ leetcode刷题的各种小tips记录
C/C++ leetcode刷题的各种小tips记录
137 0
Leetcode-每日一题769. 最多能完成排序的块(贪心)
需要怎么分割序列才是个问题,题目其实给了提示因为序列里的数只能是[0, n-1]所以选择[l, r] 连续的序列中的数一定是 [l, r] 这段区间的数字,所以我们只需要遍历数组,去找这段区间内最大的数字,即边界值r,因为他才是决定边界的数字,每次我们到达了r这个位置就表示下一段区间。
66 0
Leetcode-每日一题769. 最多能完成排序的块(贪心)