动态规划学习入门(小白零基础)
作者:@哲里的博客
本文为作者原创,转载请注明出处:https://www.cnblogs.com/zheli1/p/16847804.html
动态规划学习入门(小白零基础)
基础概念
- 如果某一问题可拆解成若干重叠子问题,即可用动态规划解决。
重叠子问题:比如斐波那契数列F(n)可分解成F(n-1)+F(n-2),而F(n-1)又可继续向下分解,而分解的过程相同,这就是重叠子问题。
- 在解决过程中不可避免的会遇到公式,用dp数组去解答问题,而这就需要明确dp数组在题目中的定义。
比如斐波那契数列求F(5),公式为F(n) = F(n-1)+F(n-2);
我们明确:dp[n]的定义为F(n)的值,dp(n) = dp(n-1)+dp(n-2);
思路入门
- 确定dp数组以及下标的含义
- 确定递推公式(dp数组表达)
- dp数组如何初始化
- 确定遍历顺序
- 如果没通过,则举例debug查错。
例题分析
[leetcode原题:使用最小花费爬楼梯](746. 使用最小花费爬楼梯 - 力扣(LeetCode))
题目描述:
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
示例:
示例1:
输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
- 支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15 。
示例2:
输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。
- 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
- 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
- 支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。
解题思路:
- 首先,题目里说cost[i]是从第i阶向上爬的费用,从示例里我们能看出,真正的楼梯阶数是cost数组的长度+1。
- 我们可这样想到达楼梯顶部和什么有关系?当然是和顶部的下一阶和下下一阶有关系了,因为这是到达顶部的两种方式(题目里说可一步爬一个或两个台阶)。所以,我们设一共有n阶,爬到顶部费用为dp[n],我们要找的是它和dp[n-1],dp[n-2]的递推关系。
方法:
方法有两种,这里都以Java为编程语言实现!
方法一:
我们把dp[n]看成是爬到第n阶楼梯所要付的费用,而要爬到n阶,只有两种选择,就是从n-1阶和n-2阶,因为说最小,所以取两者之间的最小值。
递推公式:dp[n] = min{dp[n-1]+cost[n-1],dp[n-2]+cost[n-2]}
初始化:dp[0] = 0; dp[1] = 0;也就是一开始的这两个起始台阶不花钱,毕竟我只是登上,还没往上爬呢。
遍历顺序:一阶一阶往上求
代码实现:
class Solution {
public static int minCostClimbingStairs(int[] cost) {
int length = cost.length;
int[] dp = new int[length+1];
dp[0] = 0;
dp[1] = 0;
for(int i = 2;i<=length;i++){
//定义 dp[i]:到达第i层台阶所花费的最小费用
//比较条件出问题了!不应该比dp,因为dp[i-1]和dp[i-2]到达dp[i]还要花钱
if(dp[i-1] + cost[i-1] < dp[i-2] + cost[i-2]){
dp[i] = dp[i-1] + cost[i-1];
}else{
dp[i] = dp[i-2] + cost[i-2];
}
}
return dp[length];
}
}
方法二:
我们把dp[n]看成是从第n阶往上爬要付的费用。
递推公式:dp[n] = min{dp[n-1],dp[n-2]} + cost[n]
初始化:dp[0] = cost[0]; dp[1] = cost[1];
遍历顺序:一阶一阶往上求
代码实现:
class Solution {
public static int minCostClimbingStairs(int[] cost) {
int length = cost.length;
int[] dp = new int[length+1];
dp[0] = cost[0];
dp[1] = cost[1];
for(int i = 2;i<length;i++){
//注意这里是i<length,没有 = ,因为爬到顶阶就好了,不需要计算从顶阶往上爬的费用鸭
if(dp[i-1]< dp[i-2]){
dp[i] = dp[i-1] + cost[i];
}else{
dp[i] = dp[i-2] + cost[i];
}
}
return dp[length-1]<dp[length-2]?dp[length-1]:dp[length-2];
}
}
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】