错误思考
初次看题,首先暴力的来看,最大子数和。那么就是将每一个数组里的数作为开头,然后向后遍历找。直到找到最大,时间O(n2),显然不合适。
于是思考有木有更好的方法,于是就开始思考有木有规律。于是想到先以第一个数为开头,然后向后遍历找到最大,然后再把开头开始一个一个减去,找到哪一个损失最小。但是显然,我这样考虑缺失了很多情况没有依据。
参考答案后重新思考
得知需要动态规划,突然恍然大悟。第一种暴力方法,存在重复计算的部分,需要把这部分重复的状态给转移下去,那么就是动态规划。
首先我们就要设计最小状态(因为动态规划就是将大问题拆分为小状态),第一种暴力方法将数组里每个数作为开头,显然,当前状态无法得知后续数为开头的情况,无法转移。因此,我们换个思路,以当前数为结尾的子数组的和的最大值,这样的话,每个状态都是继承之前数的状态,就可以设计状态转移方程了。
这里要说一下,我看到题解的另一种设计情况,就是经过这个数的子数组的和的最大值。这样的设计据作者所说产生了后效性的问题,因为经过某个数的子数组,这个数的位置在哪个位置我们是不确定的。tips:什么是无后效性,可以看该题解得知题解链接
书归正传。我们来设计方程:刚刚提到状态就是以某1个数结尾的子数组的最小和,那么设计一个dp数组,下标表示nums数组为此下标时的数为结尾。那么每个dp[i]都由dp[i - 1]转移,此时转移来的状态dp[i - 1]再加上当前的数,以及当前数本身做比较,取最大值
即 : dp[i] = max(dp[i - 1] + nums[i],nums[i])
那么最终答案是什么呢,注意:我们答案是找出最大值,但是我们状态是以某个数结尾,所以还要遍历dp数组找到最大值。
那么我们的代码就写出来了,我使用的是go语言
func maxSubArray(nums []int) int {
dp := make([]int,len(nums))
dp[0] = nums[0]
for i := 1;i < len(nums);i++ {
dp[i] = max(dp[i - 1]+nums[i],nums[i])
}
ans := -9999999
for i := range dp {
ans = max(ans,dp[i])
}
return ans
}
func max(a int,b int) int {
if a > b {
return a
}else {
return b
}
}
标签:状态,题目,思考,nums,int,最大值,数组,动态,dp
From: https://www.cnblogs.com/jiaomaster/p/16714956.html