![531f5035a6d0b8409ade742473800bce.png](https://img-blog.csdnimg.cn/img_convert/531f5035a6d0b8409ade742473800bce.png)
动态规划是算法里一个很重要的思想,在腾讯,网易等各大公司的笔试面试中经常遇到。
动态规划的思想是将一个问题分解为若干个子问题,对每个子问题求最优解,前一个子问题的最优解,为下面的子问题提供了有效信息,依次解决子问题,最后一个子问题就是初始问题的最优解。动态规划应用于子问题重叠的情况,子问题的划分是通过递归实现。为了避免子问题的重复计算,保证每个子问题只求解一次,会将解保存在数组中。
![75939f8a85bcfd24a24af9efb93cdf2f.png](https://img-blog.csdnimg.cn/img_convert/75939f8a85bcfd24a24af9efb93cdf2f.png)
动态规划的基本步骤如下:
1.刻画一个最优解的结构特征;
2.递归定义最优解的值;
3.计算最优解的值,通常采用自底向上的方法。
![76ba5ffd647d09199b6bb6dac9252ee5.png](https://img-blog.csdnimg.cn/img_convert/76ba5ffd647d09199b6bb6dac9252ee5.png)
那么,什么时候采用动态规划的思想呢?动态规划的问题一般有两个特征:(1)最优子结构。如果一个问题的最优解包含子问题的最优解,那么该问题就具有最优子结构;(2)重叠子问题。如果递归算法反复计算相同的子问题,那么该问题具有重叠子问题。如果在递归的每一步都生成新的子问题,那么要用分治法解决。
我们来看下面这道2017年腾讯实习生笔试题:
![74ef86da3539cc9d931b3b5b8d25527b.png](https://img-blog.csdnimg.cn/img_convert/74ef86da3539cc9d931b3b5b8d25527b.png)
求解最长回文串,即正序和逆序一样,可以将s的逆序表示出来,求逆序s和正序s的最长公共子序列,该最长公共子序列即最长的回文串。那什么是最长公共子序列呢?
![1bda829f5024f34baef7f1f28e05880b.png](https://img-blog.csdnimg.cn/img_convert/1bda829f5024f34baef7f1f28e05880b.png)
![96bdfbdcb8faae2951694fc288beb29f.png](https://img-blog.csdnimg.cn/img_convert/96bdfbdcb8faae2951694fc288beb29f.png)
接下来,该问题就转化成了求最长公共子序列的问题,而求解此类问题,就用到了动态规划。求最长公共子序列,思想如下:
![fe3565bd51676b5f4f33fb978b2a7221.png](https://img-blog.csdnimg.cn/img_convert/fe3565bd51676b5f4f33fb978b2a7221.png)
递推式如下,c[i,j]表示(x1,x2....xi) 和 (y1,y2...yj) 的最长公共子序列的长度。
![cea6ace6e6ce530ce12ea479c3bdddd8.png](https://img-blog.csdnimg.cn/img_convert/cea6ace6e6ce530ce12ea479c3bdddd8.png)
如果不采用动态规划,只用递归,代码如下:
![2dc0f6bb2ae004ee3388981768522c6b.png](https://img-blog.csdnimg.cn/img_convert/2dc0f6bb2ae004ee3388981768522c6b.png)
提交运行后会显示超时运行。因为子问题被重复计算,LCS(s,i-1,rs,j)和LCS(s,i,rs,j-1)都包含了子问题LCS(s,i-1,rs,j-1)。因此下面采用动态规划来解决。
![e40c42805b9d107df3a116f4163d9faa.png](https://img-blog.csdnimg.cn/img_convert/e40c42805b9d107df3a116f4163d9faa.png)
![b912329c49e83777c8caa3aa37ded9f3.png](https://img-blog.csdnimg.cn/img_convert/b912329c49e83777c8caa3aa37ded9f3.png)
在上述代码中,D[i][j]代表大小为i+1*j+1的数组,为什么要+1呢?这里用0表示无元素,所以初始化阶段,数组值如下:
![44671c50307fd923a58d9ffdbe696d76.png](https://img-blog.csdnimg.cn/img_convert/44671c50307fd923a58d9ffdbe696d76.png)
然后循环,依次把二维数组填满即可。
总结一下,所谓动态规划,就是在解决具有最优子结构和重复子问题两种特性的问题时,把求解子问题的递归方法改成用数组保存结果的方法,数组的值不再用递归求得,而是用递推公式求得,然后就可以直接查表实现。
参考来源:
[1] 算法导论
[2]https://www.cnblogs.com/hapjin/p/5572483.html
[3]http://blog.csdn.net/baidu_28312631/article/details/47418773
本文所有代码均为本人编写并经过测试,如有错误或问题,欢迎留言或私信指正。
![274317e67c80dd328959b56547d2f5bc.png](https://img-blog.csdnimg.cn/img_convert/274317e67c80dd328959b56547d2f5bc.png)