算法:动态规划

文章介绍了动态规划的概念,以第N个泰波那契数为例,详细阐述了动态规划的五步解题法,包括状态表示、状态转移方程、初始化、填表顺序和返回值。同时,提供了具体的代码实现,并讨论了空间优化,如使用滚动数组来减少空间复杂度。
摘要由CSDN通过智能技术生成

目录

🍉什么是动态规划?

1)题目解析,(我们以第N个泰波那契数来进行举例)

2)解读算法原理

🍉第N个泰波那契数的代码编写

🍉空间优化


🍉什么是动态规划?

动态规划就是一种解决题目的总体思路,在秋招和春招的时候会有很多面试题都会用到动态规划的求解思路,我们就来仔细的学习以下~

1)题目解析,(我们以第N个泰波那契数来进行举例)

2)解读算法原理

🍒1.状态表示

什么是状态标识?我们先来问问chatGPT,得到以下解释:

在动态规划中,状态表示指的是如何表示子问题的状态。这些状态通常用变量或数组来表示,并且它们存储着问题的某种属性或者是解的部分信息。

具体的状态表示方法取决于问题的特点和要求。一般来说,状态表示应该满足以下两个条件:

  1. 无后效性:即一个状态的值只与前面的状态有关,与未来的状态无关。这意味着在计算每个状态时,不需要考虑当前状态之后的任何状态。这样可以简化计算过程并减小时间复杂度。
  2. 最优子结构:即全局最优解包含了各个子问题的最优解。这意味着通过计算子问题的最优解,可以推导出整个问题的最优解。

常见的状态表示方式包括但不限于:

  • 单个变量:例如表示位置、时间等。
  • 数组:例如表示数量、容量等。
  • 矩阵:多维数组,用于表示相关的状态。

在动态规划问题中,选择合适的状态表示方法对于问题的求解至关重要。通过合理的状态表示,可以将复杂的问题转化为易于理解和计算的子问题,从而提高求解效率

简单来说:

我们会建立一个一维数组,我们称为dp表,然后我们把这个dp表想办法填满,填满之后,里面的某个值可能就是我们的最终结果,状态表示就是指,dp表里面的值所表示的含义

怎么来?

  • 1.题目要求——dp[i]表示:第i个泰波那契数的值
  • 2.经验+题目要求(多做题就会有所体会)
  • 3.分析问题的过程中,发现重复子问题

🍒2.状态转移方程(最难的一步)

这个通过读题就可以看出,题目中已经告诉了我们:

dp[i] = dp[i-1] + dp[i-2] + dp[i-3] 

具体如何推导,我们之后慢慢做题来看

🍒3.初始化

初始化的时候保证填表不越界,

比如泰波那契数这个题,我们要填表中的前三个,按公式来说我们就要直到第-3,-2,-1个位置
但这样肯定是越界的,所以我们要根据题目推出来。而这个题就已经给了我们前三个位置的数,分别为:0,1,1

 🍒4.填表顺序

为了填写当前状态的时候,所需要的状态已经计算过了

在这道题里,我们的填表顺序是从左到右

🍒5.返回值

题目要求 + 状态表示

🍉第N个泰波那契数的代码编写

题目链接:力扣

class Solution {
public:
    int tribonacci(int n) 
    {
        // 1.创建 dp 表
        // 2. 初始化
        // 3. 填表
        // 4. 返回值

        if(n == 0) 
            return 0;
        if(n == 1 || n == 2) 
            return 1;

        vector<int> dp(n + 1);
        dp[0] = 0,dp[1] = 1,dp[2] = 1;
        for(int i = 3; i <= n; i++)
            dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
        return dp[n];
    }
};

🍉空间优化

空间优化方法会在这道题和很后面学的背包问题中进行讲解

主要是因为我们刚刚接触到动态规划,先要把重点放在前五个步骤上面
(1.状态表示;2.状态转移方程;3.初始化;4.填表顺序;5.返回值)

空间优化会着重在背包问题的文章中重点讲解

我们先来了以这道题来了解以下空间优化

我们可以用到滚动数组的方法来进行优化

我们在求某一个状态的时候,仅仅只需要直到前面的三种状态即可,
我们在求 n=4 的时候,就不会在用到0位置的数,我们在求 n=5 的时候就不会用到 0和 1位置的值所以我们在求后面的数的时,只需要前面若干个数的时候,就可以用滚动数组来求解

其时间复杂度:优化前时O(n^2),优化后时O(n);优化前时O(n),优化后时O(1)

🍒解决该题的思路:

定义四个变量,每次对其进行更新操作

注意一个细节,我们注意赋值的顺序!

class Solution {
public:
    int tribonacci(int n) 
    {
        // 1.创建 dp 表
        // 2. 初始化
        // 3. 填表
        // 4. 返回值
        if(n == 0) 
            return 0;
        if(n == 1 || n == 2) 
            return 1;

        int a = 0, b = 1, c = 1, d = 0;
        for(int i = 3; i <= n; i++)
        {
            d = a + b + c;
            // 滚动操作
            a = b;
            b = c;
            c = d;
        }
        return d;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值