代码随想录算法训练营第三十八天 | 动态规划理论基础、 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

本文详细介绍了动态规划在解决斐波那契数列、爬楼梯和最小花费爬楼梯问题中的应用,包括dp数组的定义、递推公式、初始化和遍历顺序,同时展示了两种空间复杂度优化的方法——常规和状态压缩。

动态规划理论基础

文章链接:动态规划理论基础
思想:动态规划五部曲-

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

Leetcode 509.斐波那契数

题目链接:509.斐波那契数
递归法解题思路:递归法比较简单就不说了,就是按着他给的题意初始化,然后设计跳出条件,并进入递归
动态规划解题思路:首先确定dp数组以及下标的含义,dp数组的含义就是斐波那契数列,下标为i就是第i个斐波那契数。递推公式就是dp[i] = dp[i - 1] + dp[i - 2],初始化就是dp[0] = 0, dp[1]。然后遍历顺序就是从前往后遍历。第五个打印数组没啥问题

动态规划法:

class Solution {
public:
    int fib(int n) {
        if(n <= 1) return n;
        vector<int> dp(n + 1);
        dp[0] = 0, dp[1] = 1;

        for(int i = 2; i <= n; i++) dp[i] = dp[i - 1] + dp[i - 2];

        return dp[n];

    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(n)

动态规划状态压缩法:


class Solution {
public:
    int fib(int n) {
        if(n <= 1) return n;
        int dp[2];
        dp[0] = 0, dp[1] = 1;

        for(int i = 2; i <= n; i++) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(1)

递归法:

class Solution {
public:
    int fib(int n) {
        if(n < 2) return n;
        return fib(n - 1) + fib(n - 2);
    }
};
  • 时间复杂度为O(2^n)
  • 空间复杂度为O(n)

Leetcode 70.爬楼梯

题目链接:70.爬楼梯
解题思路:类似斐波那契数,dp数组以及下标含义为爬到第i层阶,有dp[i]种方法,递推公式为dp[i] = dp[i-1] + dp[i-2],初始化的话限制了不会出现0的情况,因此初始化为dp[1] = 1, dp[2] = 2即可;遍历顺序为从前往后开始遍历

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

        for(int i = 3; i <= n; i++) dp[i] = dp[i-1] + dp[i-2];


        return dp[n];
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(n)

状态压缩:

class Solution {
public:
    int climbStairs(int n) {
        if(n <= 1) return n;
        
        int dp[2];
        dp[0] = 1, dp[1] = 2;
        for(int i = 3; i <= n; i++) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(1)

Leetcode 746.使用最小花费爬楼梯

题目链接:746.使用最小花费爬楼梯
解题思路:dp数组以及下标的含义为,到达第i个台阶所花费的最少体力为i,只有开始爬的时候才消耗体力,所以递推公式为dp[i] = min(dp[i-1] + cost[I-1], dp[i-2] + cost[I-2]);初始化为dp[0] = 0 , dp[1]=0,因为可以选择第0个位置或者第1个位置开始爬楼梯。遍历顺序为从前往后遍历。

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

        
        return dp[cost.size()];
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(n)

状态压缩:

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        if(cost.size() <= 2) return min(cost[0], cost[1]);

        int dp[2];
        dp[0] = 0, dp[1] = 0;
        for(int i = 2; i <= cost.size(); i++) {
            int sum = min(dp[1] + cost[i-1], dp[0] + cost[i-2]);
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(1)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值