js + leetcode刷题:No.53 最大子序和

题目:

(面试题42. 连续子数组的最大和;面试题 16.17. 连续数列 均为改题,要求不同解法)

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

解法:

// Solution One -- 只循环一次,复杂度为O(n),比下面的循环多次要简单方便
var maxSubArray = function(nums) {
    let max = nums[0], min = 0, sum = 0
    // sum与min之间的差为目前最大值
    for(let i = 0,len = nums.length; i < len; i++){
        sum += nums[i]
        max = Math.max(max, sum-min)
        min = Math.min(sum, min)
    }
    return max
};

// Solution Two -- 循环两次
var maxSubArray = function(nums) {
    let len = nums.length
    if(len <= 1) return nums
    let max = nums[0]
    for(let i = 0; i < len; i++){
        let count = nums[i]
        max = max > count ? max: count
        for(let j = i+1; j < len; j++){
            count += nums[j]
            max = max > count ? max: count
        }
    }
    return max
};

// Solution Three -- 分治法
/*
当最大子数组有 n 个数字时:

若 n==1,返回此元素。
left_sum 为最大子数组前 n/2 个元素,在索引为 (left + right) / 2 的元素属于左子数组。
right_sum 为最大子数组的右子数组,为最后 n/2 的元素。
cross_sum 是包含左右子数组且含索引 (left + right) / 2 的最大值。

*/
var maxSubArray = function(nums){
    return maxSubArrayHelper(nums, 0, nums.length - 1)
}

var maxSubArrayHelper = function(nums, left, right){
    if(left === right) return nums[left]
    let mid = Math.floor((left + right) /2)
    let leftMax = maxSubArrayHelper(nums, left, mid),
        rightMax = maxSubArrayHelper(nums, mid+1, right),
        cross_num = maxSubArrayCrossNum(nums, left, right, mid)
    return Math.max(leftMax, cross_num, rightMax)
}

var maxSubArrayCrossNum = function(nums, left, right, mid){
    if(left === right) return nums[left]
    let count = 0,leftSubNum = rightSubNum = Number.MIN_SAFE_INTEGER
    for(let i = mid; i > left - 1; --i){
        count += nums[i]
        leftSubNum = Math.max(count, leftSubNum)
    }
    count = 0
    for(let j = mid + 1; j < right + 1; ++j){
        count += nums[j]
        rightSubNum = Math.max(count, rightSubNum)
    }
    return leftSubNum + rightSubNum
}


// Solution Four -- 动态规划
/*
    以子序列的结束节点为基准,先遍历出以某个节点为结束的所有子序列,因为每个节点都可能
会是子序列的结束节点,因此要遍历下整个序列
*/
// 时间最快,内存最小
var maxSubArray3_1 = function(nums){
    // 在每一个扫描点计算以改点数值为结束点的子数列的最大和
    let max_ending_here = max_so_far = nums[0]
    for(let i = 1; i < nums.length; i++){
        // 以每个位置为重点的最大子序列,都是基于前一位置的最大子数列计算得出
        max_ending_here = Math.max(nums[i], max_ending_here + nums[i])
        max_so_far = Math.max(max_so_far, max_ending_here)
    }
    return max_so_far
}
// ===> 可以转化为下列形式
var maxSubArray3_2 = function(nums){
    let res = nums[0], sum = 0
    for(let num of nums){
        sum = sum+num > num ? sum+num : num
        res = Math.max(res, sum)
    }
    return res
}

// 官方还提供了一种  贪心算法  思路,现在还不知道怎么理解,包括动态规划也是刚入脑袋不久的词,希望有时间可以补充
发布了67 篇原创文章 · 获赞 8 · 访问量 6336

猜你喜欢

转载自blog.csdn.net/qq_34425377/article/details/105016632
今日推荐