1. 题目与解析
给定一个数组
nums,将其划分为两个连续子数组left和right, 使得:
left中的每个元素都小于或等于right中的每个元素。
left和right都是非空的。
left的长度要尽可能小。在完成这样的分组后返回
left的 长度 。用例可以保证存在这样的划分方法。
输入: nums = [5,0,3,8,6]
输出: 3
解释: left = [5,0,3],right = [8,6]
输入: nums = [1,1,1,0,6,12]
输出: 4
解释: left = [1,1,1,0],right = [6,12]
根据题意,如果想在满足题意的情况下将数组分为两部分,只需要保证left中的最大值比right中的最小值还要小就可以了,因此,我们只需要找到每一位置i对应的leftMax与rightMin进行比较就可以得到答案。从开始到位置i的最值可以借助dp动态规划的思想进行求解,我们只需要比较nums[i]与leftMax[i-1],并且取其中更大的一个赋予leftMax[i]即可得到答案。
leftMax[0] = nums[0];
for (int i = 1; i < len; i++) {
leftMax[i] = Math.max(leftMax[i-1], nums[i]);
}
rightMax求解的思路与上面是一致的只是顺序是从后向前反过来而已。
rightMin[len-2] = nums[len-1];
for (int i = len - 3; i >= 0; i--) {
rightMin[i] = Math.min(rightMin[i+1], nums[i+1]);
}
这是简单的涉及到范围的动态规划方法的使用,可以在平时练习的过程中加一总结与归纳。
2. 题解
class Solution {
public int partitionDisjoint(int[] nums) {
int len = nums.length;
int[] leftMax = new int[len], rightMin = new int[len];
leftMax[0] = nums[0];
for (int i = 1; i < len; i++) {
leftMax[i] = Math.max(leftMax[i-1], nums[i]);
}
rightMin[len-2] = nums[len-1];
for (int i = len - 3; i >= 0; i--) {
rightMin[i] = Math.min(rightMin[i+1], nums[i+1]);
}
for (int i = 0; i < len; i++) {
if (leftMax[i] <= rightMin[i]) {
return i + 1;
}
}
return -1;
}
}
另外,我们可以选择性的维护leftMax与rightMin中的一个,另一个的维护过程与求解过程结合到一起,从而减小时间复杂度与空间复杂度。