【JS每日一算法:剑指Offer系列】🟨186.环形子数组的最大和(取反)

74 阅读2分钟

给定一个长度为 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​​​​​​​

题解:

个人博客

更多JS版本题解点击链接关注该仓库👀

/**
 * @description: 取反  TC:O(n)  SC:O(1)
 * @author: JunLiangWang
 * @param {*} nums 给定数组
 * @return {*}
 */
function negate(nums) {
    /**
     * 本题与53.最大子数组和有些相似,但此处为环形数组,
     * 环形数组最大子数组和与一般数组的最大子数组和不同
     * 的地方在于环形数组最大子数组元素可能存在首尾两端,
     * 如下:
     * 环形数组最大子数组可能: M M M * * * * M M
     * 
     * 其实我们可以换一种思路,上述 * * * * 是否就是数组中
     * 最小子数组和呢?数组总和-最小子数组和,不就是首尾
     * 两端最大子数组和的情况吗?
     * 
     * 因此环形数组最大子数组和则等于:
     * Max(数组总和-最小子数组和,最大子数组和)
     * 
     * 分别对应以下两种情况:
     * 1.最大元素处于首位两端:M M M * * * * M M M
     * 2.最大元素连续:       * M M M M M * * * *
     * 
     */
    // 记录数组最大子数组和
    let max = nums[0],
        // 记录数组最小子数组和
        min = nums[0],
        // 记录数组总和
        sum = 0,
        // 当前连续元素最大总和
        sumMaxElement = 0,
        // 当前连续元素最小总和
        sumMinElement = 0
    // 遍历数组元素
    nums.forEach((val) => {
        // 计算数组最大子数组和
        sumMaxElement = Math.max(sumMaxElement + val, val)
        max = Math.max(max, sumMaxElement)
        // 计算数组最小子数组和
        sumMinElement = Math.min(sumMinElement + val, val)
        min = Math.min(min, sumMinElement)
        sum += val
    })
    // 如果数组最大子数组和小于等于0,证明数组总和也小于0
    // 因此直接返回max,否则比较
    return max > 0 ? Math.max(max, sum - min) : max
}