例题1 使用最小花费爬楼梯
https://leetcode.cn/problems/min-cost-climbing-stairs/description/
class Solution {
public int minCostClimbingStairs(int[] cost) {
int n = cost.length;
int[] dp= new int[n+1];
for(int i=2;i<n+1;i++){
dp[i]=Math.min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1]);
}
return dp[n];
}
}
例题2不同路径
https://leetcode.cn/problems/unique-paths/description/
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
//初始化
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];
}
}
例题3 整数拆分
class Solution:
def integerBreak(self, n: int) -> int:
dp=[1 for _ in range(n+1)]
for i in range(3,n+1):
for j in range(1,i):
dp[i]=max(dp[i],j*(i-j),j*dp[i-j])
return dp[n]
例题4 不同的二叉搜索树
class Solution {
public int numTrees(int n) {
int[] dp=new int[n+1];
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];
}
}
例题5 01背包
-
dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
-
那么可以有两个方向推出来dp[i][j],
不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。)
放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值
所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
-
初始化:
dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。
当 j < weight[0]的时候,dp[0][j] 应该是 0,因为背包容量比编号0的物品重量还小。
当j >= weight[0]时,dp[0][j] 应该是value[0],因为背包容量放足够放编号0物品。 -
滚动数组
表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);
dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);- 背包容量是从小到大,目的是 倒序遍历是为了保证物品i只被放入一次
for(int i = 1; i < weight.size(); i++) { // 遍历物品
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
例题6 分割等和子集
https://leetcode.cn/problems/partition-equal-subset-sum/description/
class Solution {
public boolean canPartition(int[] nums) {
int n= nums.length;
if(n<2)return false;
int sum=0,maxNum=0;
for(int num:nums){
sum+=num;
maxNum=Math.max(maxNum,num);
}
if(sum%2 != 0)return false;
int target=sum/2;
if(maxNum>target)return false;
int[][] dp=new int[n][target+1];
//初始化
for(int j=nums[0];j<=target;j++){
dp[0][j]=nums[0];
}
for(int i=1;i<n;i++){ //循环物品
for(int j=0;j<=target;j++){
if(j>=nums[i])dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i]);
else dp[i][j]=dp[i-1][j];
}
}
return dp[n-1][target]==target;
}
}
例题7 最后一块石头的重量 II
https://leetcode.cn/problems/last-stone-weight-ii/description/
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
V=(sum(stones)//2)+1
n=len(stones)
dp=[[0 for _ in range(V)] for _ in range(n)]
#初始化
for j in range(stones[0],V):
dp[0][j]=stones[0]
#循环
for i in range(1,n):
for j in range(V):
if j>=stones[i]:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-stones[i]]+stones[i])
else:
dp[i][j]=dp[i-1][j]
return sum(stones)-2*dp[-1][-1]
例题8 目标和 ****
https://leetcode.cn/problems/target-sum/description/
left-right=target
left+right=sum
left=(target+sum)/2