今天和同学聊天,他们都说动态规划有的时候总是想不出来,我说不应该啊,理解了思路的话是很简单的,同学以为我是在吹牛逼,我就想今天一定要发表一篇文章 让大家也牛逼牛逼。
以下面这个题为例:
这个题是leetcode上的53 最大子数组和求和:
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1] 输出:1
示例 3:
输入:nums = [5,4,-1,7,8] 输出:23
首先声明一点,这道题动态规划并不是最优的解法,但是本文是为了讲动态规划才讲解这道题的,我认为这道题讲解起来更简单一些。
百度了的朋友都知道,动态规划是将一个大问题拆分成多个子问题,然后解决最优解的算法。动态规划几乎是存在套路的,我总结的步骤如下:
1.将题中给的大问题拆分成小问题来分析,可以通过制表。
2.将分析后的小问题来想出解题思路最后循环遍历求解大问题,对表求解。
例题中的问题是求最大的连续子数组和,那么我们可以从问题出发,他的返回值是一个sum。
那么循环中肯定会有给sum=.......结尾是 return sum;
其次它这个是 '连续的'子数组 那么你每次需要定义一个pre来存储临时你找到的这个最大和
也就是在这个一重循环(一般题都要求时间复杂度是O(N))也就是循环中 pre = ......;应该放在sum前 这样才可以为下面的sum来赋你临时的这个最大的值 。
最后我们只需要遍历这个小问题的求解思路来拓展成这个大问题就可以求解问题成功了。
解题方法(C++):
我在这个题目求解sum的基础上增加了 返回求解和的索引。
int maxSubArray(vector<int>& nums) {
int sum = nums[0];
int pre = 0;
int index = 0;
int k = 0;//用来代替sum的返回值,下面返回索引时会把sum归0;
for(int i = 0;i < nums.size();i++){
pre = max(nums[i],nums[i] + pre);
if(sum>pre) sum = sum;
else{
sum =pre;
index = i;
}
}
k = sum;//
while(sum>0){//查找最大子序列下标
sum = sum - nums[index];
cout<<index<<" ";
index--;
}
return k;
}
以上代码中DP动态规划也就是for循环中 pre = max(nums[i],nums[i] + pre);
sum = max(sum,pre);
(和C语言更方便的地方,max为C++自带的) 题中是为了输出索引而用if判断。
但一般来说动态规划问题不会这么简单,这只是给你以后解体的一个思维,比如看到最优解这种,就用DP就OK,一般的动态规划在制表的时候会涉及一个叠加的问题,但是理解动态规划的思想应该没什么问题了。还是那句话 熟能生巧 多做题你会变得更强。