LC-918. 环形子数组的最大和

143 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。

环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。

子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], ..., nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。

示例 1:

输入: nums = [1,-2,3,-2]
输出: 3
解释: 从子数组 [3] 得到最大和 3

示例 2:

输入: nums = [5,-3,5]
输出: 10
解释: 从子数组 [5,5] 得到最大和 5 + 5 = 10

示例 3:

输入: nums = [3,-2,2,-3]
输出: 3
解释: 从子数组 [3][3,-2,2] 都可以得到最大和 3

提示:

  • n == nums.length
  • 1 <= n <= 3 * 104
  • -3 * 104 <= nums[i] <= 3 * 104

题解

这道题还是比较考察思路的,在上一道题LC-53. 最大子数组和

  • 我们可以找到 无环状态下最大值

  • 相应的我们也可以找到 无环状态下最小子数组和

如何考虑有环状态呢?

对有两种情况进行比较大小。

  • 情况1

    获取 无环状态下最大值

    image.png

  • 情况2

    我们知道一个公式: (最大值 = 数组总和 - 最小值)

    若想求最大值,就是 总和 减去 最小的 就是 最大值。

    • 但是会出现一种情况,就是数组里全是 负数

      这里我们会对这种情况处理的,其实就等于情况1的 无环状态下最大值

    此时就会解决 有环状态 的情况。

    image.png

我们可以看到 贪心 的效率,还是很高的。

image.png

贪心

const maxSubarraySumCircular = (nums) => {
  const numsLength = nums.length
  let sum1 = 0
  let max1 = nums[0]
  let sum2 = 0
  let min2 = nums[0]
  let sum3 = 0
  let max3 = nums[0]

  for (let i = 0; i < numsLength; i++) {
    sum3 += nums[i]
    if (sum1 >= 0) {
      sum1 += nums[i]
    } else {
      sum1 = nums[i]
    }
    if (sum2 <= 0) {
      sum2 += nums[i]
    } else {
      sum2 = nums[i]
    }

    max1 = max1 > sum1 ? max1 : sum1
    min2 = min2 < sum2 ? min2 : sum2
  }

  // 如果最小值大于0,那么将 sum3 赋值 max3
  if (min2 > 0) max3 = sum3

  // 如果最小值小于0
  if (min2 < 0) {
    // 判断最小值和sum3是否相等
    if (sum3 === min2) {
      // 如果相等,则说明nums全是负数或者0,直接找数组中最大值 给 max3 即可
      max3 = max1
    } else {
      // 如果不相等,根据公式 ( 最大 = 总和 - 最小 )
      max3 = sum3 - min2
    }
  }

  // 最后比较一下,无环和有环状态下谁最大
  return Math.max(max1, max3)
}

总结

题目 33 :注意这道题的解题思路 和 贪心 方法的使用。