目录
文章内容来自对牛客网左神课程的整理。
很多同学(包括今天之前的我)都认为动态规划很难,其实很大程度上是因为不知道动态规划是怎么从其他算法一步步优化演变来的,上来就介绍动态规划的方法论,难免接受度比较低。
“输出是最好的学习方法”,因此本文旨在整理左神课程中对动态规划的讲解,增加图示内容,一是对个人学习效果的检验,二是希望大家能真正理解并熟练运用动态规划算法。
为什么要从一道题目开始引入?
算法重在应用,相较于理论说教,在应用场景里去体会算法的优劣和演化是非常重要的。
在此文后会接连推出对经典动态规划问题的题解。
ps:要先自己理解透彻算法的计算路径再去看代码,看不懂代码是因为算法还没有理解,而不是因为其他。
首先,大部分暴力搜索问题都能优化到动态规划问题。
暴力搜索->记忆化搜索->动态规划->动态规划的进一步优化 是常见的算法优化路径。
找零钱问题:
给定数组penny,数组元素值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求换钱有多少种方法。
假设penny[]为{5,8,10,15,20},aim 为120
最简单的:暴力搜索
暴力搜索就是把所有的情况都列出,如果能得到一种方法凑成aim,就在计数器上加1.
res1、res2 等需要继续分解计算,因此可通过递归算法进行代码实现。
暴力搜索代码实现:
首先找出递归算法需要哪些数值:数组penny,数组中可以选择货币面值的起始位置index,还需要兑换多少钱aim。
即每次递归是在penny[index],penny[index+1],..penny[N-1]中寻找可兑换成aim的方法种类数。
class Exchange {
public:
int process(vector<int>penny,int index,int n,int aim){//penny为面值数组,index为数组中表示可使用货币的子数组的起始位置,
//n 为数组大小,aim为当前要兑换的面值。
int ress = 0;
if(index == n)//递归边界,当前没有零钱货币可以选择
{
ress = aim == 0?1:0;//如果aim为0,也就是在没有零钱货币可以选择并且当前需要兑换面值为0时,这种方案是可行的,则res=1;
//否则当前没有零钱可以选择去兑换aim,且aim不为0,这种情况是不可行的,因此可行的方案数res为0;
return ress;
}
else{//index<=n;