代码随想录算法训练营Day37|动态规划part01

151 阅读4分钟

动态规划理论基础

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。

动态规划的解题步骤

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

动态规划的debug技巧

打印dp数组,查看推导过程是否和设想一致。

LeetCode 509 斐波那契数

题目链接:leetcode.cn/problems/fi…

文档讲解:programmercarl.com/0509.斐波那契数.…

视频讲解:www.bilibili.com/video/BV1f5…

思路

按照五个步骤分析:

  1. 确定dp数组(dp table)以及下标的含义:dp[i]代表第i个斐波那契数
  2. 确定递推公式:dp[i] = dp[i-1] + dp[i-2]
  3. dp数组如何初始化:dp[0]=0, dp[1]=1
  4. 确定遍历顺序:从3开始由小到大遍历到n
  5. 举例推导dp数组:假设n为10,dp数组应该为0,1,1,2,3,5,8,13,21,34,55

解法

class Solution {
	public int fib(int n) {	
		int[] dp = new int[n+1];		
		dp[0] = 0;		
		if (n > 0) {		
			dp[1] = 1;		
		}		
		for (int i = 2; i <= n; i++) {		
			dp[i] = dp[i-1] + dp[i-2];		
		}		
		return dp[n];	
	}
}

LeetCode 70 爬楼梯

题目链接:leetcode.cn/problems/cl…

文档讲解:programmercarl.com/0070.爬楼梯.ht…

视频讲解:www.bilibili.com/video/BV17h…

思路

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

爬到1层有1种方法,爬到2层有两种方法,而爬到3层有几种方法呢?要爬到第3层,要么在第1层走2步,要么在第二层走1步。所以当前的状态和之前的状态有关,我们可以用动态规划。

  1. 确定dp数组(dp table)以及下标的含义:dp[i]指爬到第i层有几种方法
  2. 确定递推公式:dp[i] = dp[i-1] + dp[i-2]
  3. dp数组如何初始化:dp[1] = 1,dp[2] = 2
  4. 确定遍历顺序:根据递推公式,高层状态根据低层推导,所以由小到大遍历
  5. 举例推导dp数组:假设爬到第10层,dp数组应该是1,2,3,5,8,13,21,34,55,89 由于数组下标从0开始,我们此处为了方便,dp[0]设置为1(满足递推公式)

解法

class Solution {
	public int climbStairs(int n) {	
		int[] dp = new int[n+1];		
		dp[0] = 1;		
		dp[1] = 1;		
		for (int i = 2; i <= n; i++) {		
			dp[i] = dp[i-1] + dp[i-2];		
		}		
		return dp[n];	
	}
}

LeetCode 746 使用最小花费爬楼梯

题目链接:leetcode.cn/problems/mi…

文档讲解:programmercarl.com/0746.使用最小花费…

视频讲解:www.bilibili.com/video/BV16G…

思路

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

要爬到下标为2台阶,可以从0开始爬并支付cost[0],或者从1开始爬支付cost[1]。而我们需要最小花费,那么就在其中选取最小值。

  1. 确定dp数组(dp table)以及下标的含义:dp[i]指爬到第i层最小的花费。题目要求爬到顶部,所以dp长度比cost大1
  2. 确定递推公式:dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])
  3. dp数组如何初始化:dp[0] = 0,dp[1] = 0
  4. 确定遍历顺序:根据递推公式,高层状态根据低层推导,所以由小到大遍历
  5. 举例推导dp数组:假设cost数组为10,15,20。dp[2]=min(10,15)=10,dp[3]=min(10+20, 0+15)=20

解法

class Solution {
	public int minCostClimbingStairs(int[] cost) {	
		int[] dp = new int[cost.length+1];		
		dp[0] = 0;		
		dp[1] = 0;		
		for (int i = 2; i < dp.length; i++) {		
			dp[i] = Math.min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);		
		}		
		return dp[dp.length-1];	
	}
}

今日收获总结

今日学习2小时,要用动态规划的标志就是当前状态可以由前面的状态推导