动态规划基础练习(lc509,lc70,lc746,lc62,lc63,lc343,lc96)

Posted _BitterSweet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划基础练习(lc509,lc70,lc746,lc62,lc63,lc343,lc96)相关的知识,希望对你有一定的参考价值。

力扣509.斐波那契数

题目描述

在这里插入图片描述

思路分析

  • dp【i】的含义就是第 i 个斐波那契数的值
  • 递推公式:dp【i】= dp【 i - 1】 + dp 【 i - 2】
  • 初始化:dp【0】= 0 dp【1】 = 1

代码实现

普通版

class Solution {
public:
    int fib(int n) 
    {
        if(n == 0 || n== 1) return n;
        vector<int> dp(n+1,0);
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2; i < dp.size(); i++)
        {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
};

优化版(空间复杂度优化到O(1))

class Solution {
public:
    int fib(int n) 
    {
        if(n < 2) return n;
        int first = 0,second = 0,third = 1;
        for(int i = 2; i<= n; i++)
        {
            first = second;
            second = third;
            third = first + second;
        }
        return third;
    }
};

力扣70.爬楼梯

题目描述

在这里插入图片描述

思路分析

  • dp【i】的含义是爬到第 i 层楼,存在dp【i】种方法
  • 递推公式:dp【i】= dp【 i - 1】 + dp 【 i - 2】
  • 不考虑dp【0】初始化,只初始化dp【1】= 1,dp【2】 = 2,从3开始递推

代码实现

普通版

class Solution {
public:
    int climbStairs(int n) 
    {
        if(n <= 1) return n;
        vector<int> dp(n+1,0);
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3; i<= n; i++)
        {
            dp[i] = dp[i-2] + dp[i-1];
        }
        return dp[n];

    }
};

优化版(空间复杂度优化到O(1))

class Solution {
public:
    int climbStairs(int n) 
    {
        if(n <= 1) return n;
        vector<int> dp(n+1,0);
        int first = 0,second = 1,third = 2;     
        for(int i = 3; i<= n; i++)
        {
            first = second;
            second = third;
            third = first + second;
        }
        return third;
    }
};

力扣746.使用最小花费爬楼梯

题目描述

在这里插入图片描述

思路分析

  • 这道题刚开始一直没看懂题意什么意思,理解之后总结就是:要么第一步不收费,要么最后一步不收费
  • dp【i】的含义是到达第 i 个台阶所花费的最少的体力
  • 递推公式:dp【i】 = min(【dp【i - 1】, dp【i - 2】) + cost【i】
  • 初始化:dp【0】 = cost【0】 dp【1】 = cost【1】
  • 从前到后遍历cost数组

代码实现

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) 
    {
        vector<int> dp(cost.size(),0);
        dp[0] = cost[0];
        dp[1] = cost[1];
        for(int i = 2;i < cost.size(); i++)
        {
            dp[i] = min(dp[i-2],dp[i-1]) + cost[i];
        }
        return min(dp[cost.size()-1],dp[cost.size()-2]);

    }
};

力扣62.不同路径

题目描述

在这里插入图片描述

思路分析

  • 机器人起点(0,0)终点(m-1,n-1)
  • dp【i】【j】含义:表示从(0,0)出发到(i,j)有dp【i】【j】条不同的路径
  • 所以路径来源就是一条横向的,一条纵向的,即dp【i-1】【j】和dp【i】【j-1】
  • 递推公式:dp【i】 = dp【i - 1】【j】 + dp【i】【j - 1】
  • 初始化
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
  • 从左到右遍历
for (int i = 1; i < m; i++) 
{
 for (int j = 1; j < n; j++) 
 {
 dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
 }
}

代码实现

class Solution {
public:
    int uniquePaths(int m, int n) 
    {
        vector<vector<int>> dp(m,vector<int>(n,0));

        for(int i = 0;i < m; i++) dp[i][0] = 1;
        for(int j = 0;j < n; j++) dp[0][j] = 1;

        for(int i = 1;i < m; i++)
        {
            for(int j = 1; j < n; j++)
            {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
};

力扣63.不同路径Ⅱ

题目描述

在这里插入图片描述

思路分析

  • 因为加入了障碍物,所以我们只需要加几条特判语句,大体思路与上题没有什么变化
  • dp【i】【j】含义:表示从(0,0)出发到(i,j)有dp【i】【j】条不同的路径
  • 递推公式:
if (obstacleGrid[i][j] == 0) 
{ // 当(i, j)没有障碍的时候,再推导dp[i][j]
 dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
  • 初始化:开辟一个二维数组
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
  • 遍历顺序:从左到右 一层一层
for (int i = 1; i < m; i++) 
{
 for (int j = 1; j < n; j++) 
 {
 if (obstacleGrid[i][j] == 1) continue;
 dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
 }
}

代码实现

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& nums) 
    {
        int m = nums.size();
        int n = nums[0].size();
        vector<vector<int>> dp(m,vector<int>(n,0));

        for(int i = 0; i < m && nums[i][0] == 0; i++) dp[i][0] = 1;
        for(int j = 0; j < n && nums[0][j] == 0; j++) dp[0][j] = 1;

        for(int i = 1; i < m; i++)
        {
            for(int j = 1; j < n; j++)
            {
                if(nums[i][j] == 1) continue;
                dp[i][j] = dp[i-1][j] +dp[i][j-1];
            }
        }

        return dp[m-1][n-1];

    }
};

力扣343.整数拆分

题目描述

在这里插入图片描述

思路分析

  • dp【i】的含义:拆解数字 i,得到的最大乘积dp【i】
  • 怎么得到dp【i】:第一种:拆解 j,j * (i - j )
  • 第二种:拆解(i - j),j * dp【i - j】
  • 递推公式
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
  • 初始化:没有必要初始化dp【0】,dp【1】,dp【2】 = 1
  • 遍历顺序:i 从3开始,j 从 1枚举
for (int i = 3; i <= n ; i++) 
{
 for (int j = 1; j < i - 1; j++) 
 {
 dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
 }
}

代码实现

class Solution {
public:
    int integerBreak(int n) 
    {
        vector<int> dp(n+1, 0);
        dp[2] = 1;
        for(int i = 3; i <= n; i++)
        {
            for(int j = 1; j < i - 1; j++)
            {
                dp[i] = max(dp[i],max((i - j) * j, j * dp[i - j]));
            }
        }
        return dp[n];

    }
};

力扣96.不同的二叉搜索树

题目描述

在这里插入图片描述

思路分析

在这里插入图片描述

代码实现

class Solution {
public:
    int numTrees(int n) 
    {
        vector<int> dp(n+1, 0);

        dp[0] = 1;

        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= i; j++)
            {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp[n];
    }
};

以上是关于动态规划基础练习(lc509,lc70,lc746,lc62,lc63,lc343,lc96)的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录|day38|动态规划part01● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

[编程题] lc 最小路径-动态规划

基础链表问题练习2

[LC] 746. Min Cost Climbing Stairs

基础链表问题练习1

算法 LC 动态规划 - 最大递增子序列