前言
这是五月集训的第二十八日,今日的训练内容是 动态规划
解题报告
动态规划问题的解题过程一般都是以下的5个过程
- 设计状态
- 写出状态转移方程
- 设定初始状态方程
- 执行状态转移
- 返回最终的解
1.力扣70
原题链接
题目概述
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
解题思路
一道在过去就曾经做过题目,而这一次做有了新的感悟,有了新的方法,感到非常的满意。一道看起来很简单的题目,思考的过程如下:因为每一步可以前进的步数一共只有两种,走一步或者走两步,所以假设我们现在处于第n
层的位置,那么可以只靠一步走到这一格的可能性也就只有两种,从第n-1
格走一步走到当前的格子里,n-2
层的位置走两格一步走到当前的格子里。现在有一点递归的感觉了,好,直接递归求解,这就是一个典型的斐波那契数列的问题了。超时啦!!还记得上一次做这个题目的时候就用了投机取巧的办法,把超时的项额外列出来就过了。
现在再重新回来思考就发现了,其实计算的过程有太多的重复了。这个递归其实每一次往后多计算哪怕那么一项,前面的计算过程都会重复一遍,而计算过程中算出来的每一项的数据都不会保留,那么明显在下一次递归之后又要重新再算一遍,这个时间复杂度可太可怕了。那么不妨定义一个数组,把每一次递归的结果都保存在其中,这样递归接下来的部分时,直接调用函数中的数据就可以了。(当然如果想要更加简单其实定义一个斐波那契数列的数组返回数组的值也是可以的,可以不使用递归)。
源码剖析
int f[46]={0};
int climbStairs(int n){
if(n<=2) return n;
else{
if(f[n]==0)
f[n] = climbStairs(n-1)+climbStairs(n-2);
}
return f[n];
}
2.力扣53
原题链接
题目概述
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
解题思路
定义一个数组用来储存以当前的整数作为最后一个元素的子数组中,累计和最大的和,也就是到目前这个元素为止的最大子数组和。具体的实现方法就是:当前的最大数组和其实一共只有两种情况,也就是当前的数组元素不与前面的数据相连,即子数组就是本身;或者子数组与前面的数组相连了,那么这个时候如果想要子数组和最大其实就直接用自身的数值加上前一项的最大子数组和就可以了。又可以使用递归来实现了,当然使用一个循环把所有的数据填入数组中也是可以的。
源码剖析
int max(int a,int b){
return a>b?a:b;
}
int maxSubArray(int* nums, int numsSize){
int m[100001];
int i;
int ret=nums[0];
m[0]=nums[0];
for(i=1;i<numsSize;i++){
m[i]=max(m[i-1]+nums[i],nums[i]);
ret = max(ret,m[i]);
}
return ret;
}
后两题暂做记录。