数组分块后排序结果不变

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

难度困难185

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

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

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

示例 1:

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

示例 2:

1
2
3
4
5
输入: arr = [2,1,3,4,4]
输出: 4
解释:
我们可以把它分成两块,例如 [2, 1], [3, 4, 4]
然而,分成 [2, 1], [3], [4], [4] 可以得到最多的块数。

注意:

  • arr的长度在[1, 2000]之间。
  • arr[i]的大小在[0, 10**8]之间。

题解

可以理解为如果可以分块,那么对应分块的左边分块的最大值一定小于等于右边分块的最小值

  • 首先从左到右遍历,获取对应i之前的最大值prev[i]
  • 然后从右到左遍历,获取对应i之后的最小值next[i]
  • 比较prev[i-1] <= next[i]成立,可以进行分块,计数加1

返回计数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Solution {
public int maxChunksToSorted(int[] arr) {
int n = arr.length, cnt = 1;
int[] prev = new int[n], next = new int[n];

// 计算前缀最大
prev[0] = arr[0];
for (int i = 1; i < n; i++) {
prev[i] = Math.max(arr[i], prev[i-1]);
}
Arrays.fill(next, Integer.MAX_VALUE);

// 计算后缀最小
next[n-1] = arr[n-1];
for (int i = n-2; i>=0; i--) {
next[i] = Math.min(arr[i], next[i+1]);
}

for (int i = 1; i < n; i++) {
if (prev[i-1] <= next[i])
cnt++;
}

return cnt;
}
}
  • 时间复杂度:$O(n)$ 数组长度,三次数组长度的遍历
  • 空间复杂度:$O(n)$ 数组长度的空间复杂度,设置了两个辅助数组

image-20220813143608107


768.最多能完成排序的块II
http://example.com/2022/08/13/leetcode每日一题/768.最多能完成排序的块II/
作者
madao33
发布于
August 13, 2022
许可协议