分割数组

214 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

915. 分割数组 - 力扣(LeetCode)

给定一个数组 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^5
  • 0 <= nums[i] <= 10^6
  • 可以保证至少有一种方法能够按题目所描述的那样对 nums 进行划分。

思路

题目要求将数组分割为两部分leftrightleft中每个值都小于等于right中的值。设splitIdxleftright分割的下标, 则splitIdx左侧值小于等于右侧值,我们可以找到splitIdx左侧的最大值leftmax,然后遍历right,如果right中存在小于leftmax的值,更新splitIdx的位置,并重新找到对应的leftmax值,再遍历right,直到right中的值都大于等于leftmax,如解法一。

解法一每次都重新遍历splitIdx左右两部分,效率不高,我们可以用变量保存当前最大的值max,当nums[i]小于leftmax时,更新splitIdx = ileftmax = 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;
};