提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
动态规划是算法中比较难的一类问题,今天在这里整理一下动态规划的入门问题。
一、动态规划是什么?
动态规划往往用来求解最优解。动态规划的问题往往可以分解成多个子问题,先求解子问题,再通过子问题来得到最终问题的答案。乍一看和分治法类似,实际上确实比较类似,但动态规划分解后的子问题之间不是相互独立的,而分治法之间的子问题是相互独立的,如果用分治法去求解动态规划的问题,往往会大量重复计算已经计算过的值,而动态规划利用一个表存储每一个子问题的答案,需要的时候去表中取就行了,这就是动态规划基本的思想。
二、解决动态规划问题的主要步骤
本人对于动态规划问题主要是从以下几个方面来思考的
1 首先是确定一个表f,可能是一维的,也可能是二维的,根据实际情况决定,例如最常见的爬楼梯问题,我们可以这样设定一个表f,对于每个表中的元素f[i],代表爬到第i阶楼梯共有多少种方法。
2 第二步就是划分,也就是寻找所谓的状态转移方程的过程,对于此题,我们这样划分: 对于爬到第i阶楼梯,我们考虑是怎么到第i阶来的,即最后一次是走了一阶,还是两阶,由此我们就可以得到状态转移方程f [i] = f[i - 1] + f[i - 2]
三、入门题目
背包问题(没有在leetcode中找到原题)
爬楼梯
斐波那契数列
这两题的基本思想是一样的,上面已经提交,这里不再提及。
最大子序和
对于这题,我们令f[i]代表以当前num[i]为结尾的连续子数组的最大和。那么可以想到,如果f[i-1]小于0的话,那么会对f[i]产生负面效果,所以f[i] = max(f[i - 1], 0) + num[i];
最长上升子序列
对于这题,我们令f[i]代表以i为结尾的上升子序列中的元素个数,
划分:f[i]可能由 0 ~ i - 1中的任何一个转移过来,但是必须保证num[j]必须小于num[i],j 取0 ~ i - 1所以依次枚举0 ~ i - 1取其中的最大值,再加上1即可。
最长公共子序列
元素f[i][j]代表text1的前i个字符[0,i)和text2的前j个字符[0,j)的最长公共子序列的长度。
划分:根据第i j 个元素是否相等来划分,如果第i 和 j 的元素不相等,那么f[i][j] = max(f[i -1][j], f[i][j - 1])。
如果第text1[i] == text2[j]那么 f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1)。
总结
动态规划类的题关键在于怎么表示和怎么划分,这往往是一眼看不出来的,需要大量的经验,不过还是有一点规律可循,往往是根据上一次的状态来划分。还是多做题吧~