2021-04-23

动态规划—基础学习篇

	**动态规划在求解问题中往往是解题利器**,刷题leetcode近两个月,还没有系统学习动态规划、贪心算法、回溯等,因此接下来一段时间,小白会定期发布自己系统学习的算法,帮助自己和大家理解,话不多说,直接进入正题。
	其实查阅资料可知,动态规划无非就是两大步骤:①拆分问题;②确定状态及状态转移方程
	对于以上两大步骤,小白通过“BS有前途”的博客中讲的通俗易懂,里面的例子也都很经典,不了解的小伙伴可以去看一下:[经典算法:动态规划](https://blog.youkuaiyun.com/ailaojie/article/details/83014821)
	
	小白在本博客中就拿两道经典的leetcode题目来分享一些心得:
	经典例题①
	leetcode剑指Offer 10-1斐波那契数列
	题目如下:
	
	写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
	F(0) = 0,   F(1) = 1
	F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
	斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
	答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
	
	还未学习动态规划前,你是否第一反应就是:哇,好解决,我通过递归直接掉用返回上一层的结果,然后归于下一层使用,或者直接使用双重for循环来算出F(n-1)和F(n-2),而这样做,会让时间复杂度难以估量的高(随着问题规模的增大)
	那么,有什么好的解决办法呢?
	答案无非是,动态规划的思想,我们通过保存当前问题的解,并将这个问题的解用于下一问题解的前提,来实现求得最后问题的解,拿F(8)举例,因为要求F(8),我们从当前已知的F(0)和F(1)求起,计算出F(2),这个时候,就能通过F(1)和F(2)来求解F(3),依次计算便可,代码如下:
class Solution {
//动态规划初尝试
public:
    int fib(int n) {
    	//0、1需要单独考虑
        if(n==0) return 0;
        if(n==1) return 1;
        vector<int> dp(n+1,0);
        dp[0]=0; 
        dp[1]=1;
        for(int i=2;i<n+1;i++)
            dp[i]=(dp[i-1]+dp[i-2])%1000000007;
        return dp[n];
    }
};
时间复杂度为O(n)

斐波那契数列是一题经典的动态规划题目,从此为出发点能对动态规划有初步的了解

经典例题②(不同路径)
题目如下:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?

![图示](https://img-blog.csdnimg.cn/20210423155034396.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvbnRpbnVlX2dkdWZl,size_16,color_FFFFFF,t_70#pic_center)


状态初始化:每个第一行方格和第一列都只能从左或者只能从上方方格处到达,所以初始化第一行和第一列的方法数为1
因为每个到达每个方格的方法分别是从上方到达和从左方到达,因此可以列出动态转移方程:path[i][j]=p[i][j-1]+p[i-1][j]

代码如下:
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> paths(m,vector<int>(n));		//注意需要这样创建
        //确定初始状态,边界情况皆为初始态
        for(int j=0;j<n;j++)
        {
            paths[0][j]=1;
        }
        for(int i=0;i<m;i++)
        {
            paths[i][0]=1;
        }
        //每一个由左边方格和右边方格共同决定
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                //状态转移方程
                paths[i][j]=paths[i-1][j]+paths[i][j-1];
            }
        }
        return paths[m-1][n-1];
    }
};
时间复杂度O(n²)

值得注意的是:二维数组vector<vector >path的初始化方法需要:
vector<vector> paths(lines,vector(rows));
意为创建行长为line,列宽为rows的二维数组,将这两个向量再用vector包裹起来
调试运行时不断报超时错误,是因为没有正确初始化导致循环无法停止,需要特别注意

今天是系统动态规划学习的第一天,是较为基础的理解和经典例题的反思,Fighting~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Astronaut_001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值