最大子数组和
题干:
给定一个数组nums[]
,求下标连续的子数组的和的最大值,nums[i]
表示第i个元素的数值,可以为负数,i从0开始递增。
nums = [-2,1,-3,4,-1,2,1,-5,4]
解题思路:
化大问题为小问题,通过局部最优解来推出全局最优解。
定义最佳状态数组: dp = []
,dp[i]表示到第个元素为止,下标连续的子数组的和的最大值。
定义下标连续的子数组的和的最大值: maxVal
,即存放最终答案。因为最大值不一定是dp最后一项。
题目分析:
如果数组长度为1
那么子元素长度也只能为1,最大子数组和为 第一个元素的值,此时dp[0]=nums[1];maxVal=nums[1]
,
最终为:dp[0]=-2; maxVal=-2
如果数组长度为2
前面已经算出了长度为1的数组的最大子数组和为dp[0]
,那么子数组和有两种情况,要么加上前面最大和dp[0]
,要么不加。最终加与不加取决于那种方式获得的值是最大的。
情况:
- 加。那么长度为2时子数组和最大值为:
dp[0]+nums[1]=-2+1=-1
- 不加。那么长度为2时子数组和最大值为:
nums[1]=1=1
取两者最大,得到至第2个元素为止,最大和为:dp[1] = max(-1,1) =1
算出最终的最大值,maxVal=max(dp[1],maxVal)= 1
如果数组长度为3
前面已经算出了长度为2的数组的最大子数组和为dp[1]
,那么最大子数组和有两种情况,要么加上前面最大和dp[0]
,要么不加。最终加与不加取决于那种方式获得的值是最大的。
情况:
- 加。那么长度为3是时,子数组和最大值为:
dp[1]+nums[2]= 1 + -3 = -2
- 不加。那么长度为3时,子数组和最大值为:
nums[2]=-3
取两者最大,得到至第3个元素为止,最大和为:dp[2] = max(-2,-3) = -2
算出最终的最大值,maxVal=max(dp[2],maxVal) = max(-2,1)= 1
如果数组长度为n
前面已经算出了长度为n
的数组的最大子数组和为dp[n-1]
,那么最大子数组和有两种情况,要么加上前面最大和dp[n-1]
,要么不加。最终加与不加取决于那种方式获得的值是最大的。
情况:
- 加。那么长度为n是时,子数组和最大值为:
dp[n-1]+nums[n]
- 不加。那么长度为n时,子数组和最大值为:
nums[n]
取两者最大,得到至第n个元素为止,最大和为:dp[n] = max(dp[n-1]+nums[n],nums[n])
算出最终的最大值,maxVal=max(dp[n-1],maxVal)
代码编写
function maxSubArray(){
/* 给定一个数组nums,求连续的最大的子数组的和为多少*/
let nums = [-2,1,-3,4,-1,2,1,-5,4]
// 定义初始状态 dp dp[i]为第i为最大的子数组和
let dp = [nums[0]]
// 状态转移方程 dp[i] = max(dp[i-1]+nums[i], nums[i]),前面最大和加上当前这个数的结果于当前这数比大小
let maxVal = nums[0]
for(let i=1;i<nums.length;i++){
dp[i] = max(dp[i-1]+nums[i],nums[i])
maxVal = max(dp[i], maxVal)
}
console.dir(dp)
return "最大子数组和为:"+maxVal+"\n"
}
/*
结果为: 6 ([4,-1,2,1])
*/
function max(a,b){
return a > b ? a : b
}
结语:
动态规划的解题思路就是化大问题为小问题。像此题,先求出1个元素时的最优解,通过第一个最优解去推出2个元素时的最优解,通过第二个最优解继续推出3个元素时的最优解。直到第n个。