题目:最大子序和
方法一:动态规划
思路分析
采用动态规划,创建动态数组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[]中找到最大值即可。
class Solution {
public int maxSubArray(int[] nums) {
//特判
if(nums == null || nums.length == 0) return 0;
//初始化
int len = nums.length;
int[] dp = new int[len];
dp[0] = nums[0];
int maxSubSum = nums[0]; //记录dp数组中的最大值
//状态转移
for(int i = 1; i < len; i ++){
dp[i] = Math.max(0,dp[i-1]) + nums[i]; //填充dp[]数组
maxSubSum = Math.max(maxSubSum,dp[i]); //更新最大值
}
return maxSubSum;
}
}
方法二:贪心算法
先diss下上述的动态规划。在动态规划中,单独拿出一块O(n)的空间来存放每段数组的dp状态值,然后在存放的同时记录最大的状态值。你细品,记录的这些dp状态值,除了最大值之外,其他的都用不着。那么不存放这些多余的状态值,只要最大值可以么?当然,不然我这么多嘴干嘛!
思路分析
- 初始化
- 定义一个当前和
curSum
,为负数的时候就清零从新累计,初始值为0; - 定义一个最大和
maxSum
,每当curSum
求出之后都要拿来比较一下,进行更新,初始值为Integer.MIN_VALUE
,保证计算第一个元素的时候maxSum
就更新为curSum
;
- 遍历,对每一个元素进行如下操作:
- 计算当前和
curSum
; - 更新最大和
maxSum
; - 更新当前和
curSum
,若为负数则清零
- 返回
class Solution {
public int maxSubArray(int[] nums) {
//特判
if(nums == null || nums.length == 0) return 0;
//初始化
int curSum = 0;
int maxSum = Integer.MIN_VALUE;
//遍历
int len = nums.length;
for(int i = 0; i < len; i++){
curSum += nums[i]; //计算curSum
maxSum = Math.max(maxSum,curSum); //更新maxSum
if(curSum < 0){ //更新curSum
curSum = 0;
}
}
return maxSum;
}
}
(可能有人会问为啥不是计算更新完curSum
,再更新maxSum
,是因为maxSum
也可能是负数,先清零的话就影响到结果了)