持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
给定一个数组 nums ,将其划分为两个连续子数组 left 和 right, 使得:
left中的每个元素都小于或等于right中的每个元素。left和right都是非空的。left的长度要尽可能小。
在完成这样的分组后返回 left 的 长度 。
用例可以保证存在这样的划分方法。
示例 1:
输入: nums = [5,0,3,8,6]
输出: 3
解释: left = [5,0,3],right = [8,6]
示例 2:
输入: nums = [1,1,1,0,6,12]
输出: 4
解释: left = [1,1,1,0],right = [6,12]
提示:
2 <= nums.length <= 10^50 <= nums[i] <= 10^6- 可以保证至少有一种方法能够按题目所描述的那样对
nums进行划分。
思路
题目要求将数组分割为两部分left和right,left中每个值都小于等于right中的值。设splitIdx为left和right分割的下标, 则splitIdx左侧值小于等于右侧值,我们可以找到splitIdx左侧的最大值leftmax,然后遍历right,如果right中存在小于leftmax的值,更新splitIdx的位置,并重新找到对应的leftmax值,再遍历right,直到right中的值都大于等于leftmax,如解法一。
解法一每次都重新遍历splitIdx左右两部分,效率不高,我们可以用变量保存当前最大的值max,当nums[i]小于leftmax时,更新splitIdx = i, leftmax = max,如解法二。
解题
解法一
/**
* @param {number[]} nums
* @return {number}
*/
var partitionDisjoint = function (nums) {
const n = nums.length;
let splitIdx = 0;
let leftmax = nums[0];
let i = 0;
let j = 0;
while (j < n) {
while (i < splitIdx) {
if (nums[i] > max) {
leftmax = nums[i];
}
i++;
}
while (j < n) {
j++;
if (nums[j] < leftmax) {
splitIdx = j;
break;
}
}
}
return splitIdx + 1;
};
解法二
/**
* @param {number[]} nums
* @return {number}
*/
var partitionDisjoint = function (nums) {
const n = nums.length;
let splitIdx = 0;
let leftmax = nums[0];
let max = 0;
for (let i = 1; i < n; i++) {
if (nums[i] < leftmax) {
splitIdx = i;
leftmax = max;
} else if (nums[i] > max) {
max = nums[i];
}
}
return splitIdx + 1;
};