动态规划(dynamic programming)

来源:互联网 发布:snmp监控linux 编辑:程序博客网 时间:2024/05/18 03:24

什么是动态规划?

给定该数组arr,arr中所有的值都为整数且不重复。每个值代表一种面值的货币。每种面值的货币可以使用任意张。再给定给一个整数aim代表要找的钱数,求换钱有多少种方法。





暴力搜索方法(利用递归)的缺点在于有很多的重复计算。比如:arr={5,10,25,1}已经使用0张5元和1张10元的情况下,后序将求:p1(arr,2,990).

当已经使用2张5元和0张10元的情况下,后续还是要求p1(arr,2,990).因为有很多的重复计算,所以暴力搜索的时间复杂度非常高!!

记忆搜索方法:重复计算的原因在于每一次的递归结果都没有记录下来,所以每一次都要重复计算。

暴力搜索方法的函数p1(arr,index,aim)其中arr是始终不变的,而index和aim是变化的,并且可以代表递归过程。p(index,aim)。

1. 利用哈希表map,每计算完一个p(index,aim)都讲结果放入map中,index和aim组成共同的key,返回结果为value。

2. 要进入一个递归过程p(index,aim),先以index和aim的key在map中查询是否已经存放value,如果存在,则直接取值,如果不存在,才进行递归计算。

下面是记忆搜索方法的代码实现:



因为本题的递归过程可以由两个变量进行表示,index和aim,所以只需要申请二维的map就可以。二维数组map[i][j]的结果代表p(i,j)的返回结果,每次进入下一次递归之前,都要先查询map是否计算过,如果计算过直接取出来用就可以。



记忆搜索方法与动态规划方法的联系:

1. 记忆化搜索方法就是某种形态的动态规划方法。复杂度也是o(aim*aim)

2. 记忆化搜索方法不关心到达某一个递归过程的路径,只是单纯地对计算过的递归过程进行记录,避免重复的递归过程。

3.动态规划的方法则是规定好每一个递归过程的计算顺序,依次进行计算,后面的计算过程严格依赖前面的计算过程。

4. 两者都是空间换时间的方法,也都有枚举的过程。区别在于动态规划规定计算顺序,而记忆搜索不用规定。


动态规划方法:

1. 其本质是利用申请的空间来记录每一个暴力搜索的计算结果。下次要用的结果的时候直接使用,而不在进行重复的递归过程。

2. 动态规划规定给每一种递归状态的计算顺序,依次进行计算。


对于上面的动态规划来说,因为不用进行枚举过程,直接使用公式dp[i][j]=dp[i][j-arr[i]]+dp[i-1][j],所以时间复杂度少了一个aim,变成了o(N*aim).



面试中遇到的暴力递归题目可以优化成动态规划方法的大体过程:

1. 实现暴力递归方法。

2. 在暴力搜索方法的函数中看看哪些参数可以代表递归过程。

3. 找到代表递归过程的参数之后,记忆化搜索的方法非常容易实现。只需要将递归过程的参数整体当做key,递归过程的值当做value,放到map中就可以了。

4. 通过分析记忆化搜索的依赖路径,进而实现动态规划。(简单的可以先得到的先计算,大部分情况下为map的第一行和第一列。)

5. 通过记忆化搜索方法改出动态规划方法,进而看看是否能化简,如果能化简,还能实现时间复杂度更低的动态规划方法。(比如说是否能推出公式)


原创粉丝点击