题目描述
给定一个数组 A,将其划分为两个不相交(没有公共元素)的连续子数组 left 和 right, 使得:
- left 中的每个元素都小于或等于 right 中的每个元素。
- left 和 right 都是非空的。
- left 要尽可能小。
在完成这样的分组后返回 left 的长度。可以保证存在这样的划分方法。
题解
不检验 all(L <= R for L in left for R in right),而是检验 max(left) <= min(right)。
算法
找出对于所有子集 left = A[:1], left = A[:2], left = A[:3], … 的最大值 max(left),也就是用 maxleft[i] 记录子集 A[:i] 的最大值。两两之间是相互关联的:max(A[:4]) = max(max(A[:3]), A[3]) 所以有 maxleft[4] = max(maxleft[3], A[3])。
同理,所有可能的 right 子集最小值 min(right) 也可以在线性时间内获得。
最后只需要快速扫描一遍 max(left) 和 min(right),答案非常明显。
class Solution {
public int partitionDisjoint(int[] A) {
int n = A.length;
int[] maxLeft = new int[n];
int[] minRight = new int[n];
int m = A[0];
for (int i = 0;i < n;i++){
m = Math.max(m,A[i]);
maxLeft[i] = m;
}
m = A[n - 1];
for (int i = n - 1;i >= 0;i--){
m = Math.min(m,A[i]);
minRight[i] = m;
}
for (int i = 1;i < n;i++){
if (maxLeft[i - 1] <= minRight[i]){
return i;
}
}
throw null;
}
}