最大子序和

Posted xiaofeng-fu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大子序和相关的知识,希望对你有一定的参考价值。

问题描述

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

示例:

 

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

 

解法一(动态规划):

用dp[i]表示第i位结尾的最大子数组的大小,那么当dp[i-1]小于0的时候,最大子数组就是dp[i]=nums[i],否则为dp[i]=dp[i-1]+nums[i],由于每个dp[i]只使用一次,我们可以只用一个dp变量来记录之前的子数组最大值,节省空间,过程中记录出现过最大值即可。

思路分析

采用动态规划,创建动态数组dp[],关键是要捋清楚dp[i]是啥,如何由之前的dp值来求当前的dp[i]?

定义状态:dp[i]表示索引从0到i的元素组成的数组中最大子序和;
初始状态:dp数组的第一个元素也就是数组的第一个元素本身,dp[0] = nums[0];
状态转移方程:如果dp[i-1]大于0,那么很显然dp[i]的值就是在其基础上再加上一个nums[i];而当dp[i-1]小于0,那么dp[i-1]与nums[i]两者的和显然不如nums[i]本身的大,由于我们要连续数组最大和,所以直接抛弃这段就可以了,从当前元素nums[i]开始累计。
因此,转移方程为:dp[i] = min{dp[i-1],0} + nums[i];
根据dp[]的初始状态和转移方程,我们可以将dp[]数组填满,每个位置上的值代表着以这个位置元素结尾的最大连续子数组的最大和。因此,只需从dp[]中找到最大值即可。

优化:由于每个dp[i]只使用一次,我们可以只用一个dp变量来记录之前的子数组最大值,节省空间,过程中记录出现过最大值即可

class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0], dp = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (dp <= 0) dp = nums[i];
            else dp += nums[i];
            max = Math.max(max, dp);
        }
        return max;
    }
}

总结:

此题还可以用分支算法,实际上,分治法的复杂度并没有动态规划方法的复杂度好。

分治法主要是递归的拆解数组为左右两部分,当拆解到一个元素时开始返回,并“组装”每两部分。





以上是关于最大子序和的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode53. 最大子序和

53.最大子序和

贪心——力扣53.最大子序和&&力扣122.买卖股票的最佳时机Ⅱ

C++ LeeCode 最大子序和

C++ LeeCode 最大子序和

TYVJ1305 最大子序和