题目描述
给定一个数组 A
,将其划分为两个不相交(没有公共元素)的连续子数组 left
和 right
, 使得:
left
中的每个元素都小于或等于right
中的每个元素。left
和right
都是非空的。left
要尽可能小。
在完成这样的分组后返回 left
的长度。可以保证存在这样的划分方法。
样例
输入:[5,0,3,8,6]
输出:3
解释:left = [5,0,3],right = [8,6]
输入:[1,1,1,0,6,12]
输出:4
解释:left = [1,1,1,0],right = [6,12]
注意
2 <= A.length <= 30000
0 <= A[i] <= 10^6
- 可以保证至少有一种方法能够按题目所描述的那样对
A
进行划分。
算法
(枚举) $O(n)$
- 定义数组 minr[i] 表示 A 中从 i 到 n - 1 的最小值,通过一次遍历来更新这个数组。
- 然后从左到右遍历数组 A,同时记录从 0 到当前位置的最大值 maxr,如果 maxr <= minr[i + 1],则返回 i + 1。
时间复杂度
- 遍历两次,故时间复杂度为 $O(n)$。
空间复杂度
- 需要 $O(n)$ 的额外空间存放最小值。
C++ 代码
class Solution {
public:
int partitionDisjoint(vector<int>& A) {
int n = A.size();
vector<int> minr(n, 100000000);
minr[n - 1] = A[n - 1];
for (int i = n - 2; i >= 0; i--)
minr[i] = min(A[i], minr[i + 1]);
int maxr = 0;
for (int i = 0; i < n - 1; i++) {
maxr = max(maxr, A[i]);
if (maxr <= minr[i + 1])
return i + 1;
}
return -1;
}
};