记录一次动态规划题目的思考过程

错误思考

53. 最大子数组和

初次看题,首先暴力的来看,最大子数和。那么就是将每一个数组里的数作为开头,然后向后遍历找。直到找到最大,时间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
			}
	}
posted @ 2022-09-21 11:52  JiaoMaster  阅读(33)  评论(0编辑  收藏  举报