开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情
什么是动态规划
动态规划是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题。
我第一次接触动态规划是:斐波那契数列。
斐波那契数列:01124.....
第一个数是0,第二个是1,第三个等于第一个+第二个
f(n)=f(n-1)+f(n-2)
那么这个题代码实现最简单是递归:
int Fibonacci(int n){
if(n<=1) return n;
return Fibonacci(n-1)+Fibonacci(n-2)
}
画图如下
这个就是递归的过程。那么我们可以发现f(2)计算了两次,f(1)计算了3次,f(0)计算了2次。而他们其实按道理只需要记录一次。所以优化1,加入map存储计算过的数。(也可以使用数组,不过如果使用数组,在比较只时候需要重新遍历数组,当数据量很大时候,不方便)
定义一个map关键字是f几,值是结果。
Map<Integer,Integer> map_flag
int Fibonacci(int n){
if(n<=1) return n;
if(map_flag.containsKey(n)){
return map_flag.get(n);
}
return map_flag.put(n,Fibonacci(n-1)+Fibonacci(n-2))
}
那么如何使用动态规划方式完成?
拆解问题:如果n=1或者n=0 f(n)确定
其他f(n)=f(n-1)+f(n-2)是动态规划的状态转移方程;
那么求解f(n)变成了求解f(n-1)+f(n-2)。
接下来是跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
分解问题:
当n=1的时候,有一种跳法,当n=2有两种,当n=3,有 n=2解法+n=1解法=3 种。 当n=4,有:n=3解法+n=2解法
那么图示如下
动态规划代码如下:
关于最小跳台阶代价
给定一个整数数cost ,其中cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用,下标从0开始。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
如果n<2 花费Math.min(cost[0],cost[1]);
如果n>2 花费当前cost+min(前面的)
dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
那么代码如下
看上去动态规划和递归一样,需要找到规律。
怎么输出最长子序列?
首先模板子序列不一定连续。那么如果当前str1的某个值和str2某值相等,那么当前值=前面值+1.
如图:假设当前A相等,那么最大序列是,A之前序列的最大序列+1.(dp[i][j]=dp[i-1][j-1]+1;)
如果当前不相等,那么其中一个字符串回退1,找到回退的最大值。(dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);)
边界条件:如果字符串为空,输出-1。然后在dp数组里面,找出这个字符子串。
你可能会疑惑,为什么会倒着加进去?因为我们是向前寻找,假设当前A相等,那么最大序列是,A之前序列的最大序列+1.
那么和子序列相关的是子串问题。
遍历数组,如果当前ij对于值相等,res++
总结:
动态规划其实就是怎么把大问题分成几个小问题,怎么通过小问题得到大问题,如果很难考虑的话,我们可以优先使用递归等方式实现,然后一步步优化。
动态规划需要找到:dp下标和含有,递推公式,怎么初始化,遍历顺序