初识动态规划算法思想

一.问题引入

以昨天在Leetcode上做的斐波那锲数列为例:

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

题目很简单,首先想到的就是直接递归来解决。但递归方法在这里会超时并且存在大数越界问题。迭代法在这道题可以AC,但翻看题解发现这道题也是做为动态规划算法的入门引例
动态规划方法:

class Solution {
    
    
    public int fib(int n) {
    
    
        if (n == 0 || n == 1) {
    
    
            return n;
        }
        long[] dp = new long[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
    
    
            dp[i] = dp[i - 1] + dp[i - 2]; //状态转移处
            dp[i] = dp[i] % 1000000007;
        }
        return (int) dp[n];
    }
}

可以看出,与传统递归方法相比,这里创建了一个新的dp数组自底而上保存每一次计算的结果,避免了每一次计算都得从头开始。
这里的状态转移方程其实就是暴力破解里面的数学表达式(一个新的状态可以由其他已经存在的状态得出,感觉有点类似于递归关系式)
这里的斐波那契数列问题严格上并不能看做动态规划问题,因为一般用动态规划解决的问题一般具有三个要素:重叠子问题、最优子结构、状态转移方程。而在这里严格上它不具有最优子结构要素,因为它的每一个子问题的解都只有一个,并不存在最优的概念。由此也可以推测,动态规划算法一般是用于求最优解的。

二.总结

在我的理解中,动态规划算法的本质还是穷举,自底而上穷举出每一个子问题的结果。但是在穷举的过程中,优化子问题的重复计算问题,同时动态规划问题的子问题必须具有最优解,然后是状态转移方程(类似暴力解法中的数学关系式)的寻找。这构成了动态规划问题的三要素:重叠子问题、最优子结构、状态转移方程
动态规划算法的一般形式就是用来求最值(最优解)自底而上逐步由子问题的最优解求得原问题的最优解。
动态规划问题模型很多,背包问题、区间模型等都属于动态规划问题(任重道远啊…)

猜你喜欢

转载自blog.csdn.net/m0_46550452/article/details/107416138