刷题的日常-最多能完成排序的块

57 阅读2分钟

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

刷题的日常-2022年10月13号

一天一题,保持脑子清爽

最多能完成排序的块

来自leetcode的 769 题,题意如下:

给定一个长度为 n 的整数数组 arr ,它表示在 [0, n - 1] 范围内的整数的排列。

我们将 arr 分割成若干 块 (即分区),并对每个块单独排序。将它们连接起来后,使得连接的结果和按升序排序后的原数组相同。

返回数组能分成的最多块数量。

示例1:

输入: arr = [4,3,2,1,0]
输出: 1
解释:
将数组分成2块或者更多块,都无法得到所需的结果。
例如,分成 [4, 3], [2, 1, 0] 的结果是 [3, 4, 0, 1, 2],这不是有序的数组。

理解题意

通过题意,我们可以将信息整理如下:

  • 题目给定一个数组,要求我们对数组分块
  • 分块后的数组进行排序之后再合并回来,应该是有序的数组
  • 返回最大的划分次数

做题思路

最直观的划分方法是,找到一个数之后,往后按递减的规则一直搜索,直到出现一个不满足递减规则的数,此时可以划为一个区域,但是我们需要保证划出来的区域的最小值要大于前一个区域的最大值,否则不满足题意无法进行划分,所以要将当前区域和之前的区域进行合并,步骤如下:

  • 开辟一个数组用于保存区域的最小值
  • 循环数组
  • 记录当前区域的最大值
  • 往后以递减的规则搜索边界
  • 边界出来之后
  • 如果有前一个边界并且当前区域最小值小于之前区域的最大值,往前一直合并
  • 返回区域的索引加1

代码实现

代码实现如下:

public class Solution {
    public int maxChunksToSorted(int... arr) {
        if (arr.length < 1) {
            return 1;
        }
        int[] min = new int[arr.length];
        int idx = -1, tmp;
        for (int i = 0; i < arr.length; i++) {
            tmp = arr[i];
            while (i + 1 < arr.length && arr[i + 1] < arr[i]) {
                i++;
            }
            arr[++idx] = tmp;
            min[idx] = arr[i];
            while (idx > 0 && min[idx] < arr[idx - 1]) {
                min[idx - 1] = Math.min(min[idx], min[idx - 1]);
                arr[idx - 1] = Math.max(arr[idx], arr[idx - 1]);
                idx--;
            }
        }
        return idx + 1;
    }
}

image.png