代码随想录day45 | 动态规划P7 | ● 70.● 322. ● 279.

70. 爬楼梯 (进阶)

卡码网:57. 爬楼梯

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

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

输入描述:输入共一行,包含两个正整数,分别表示n, m

输出描述:输出一个整数,表示爬到楼顶的方法数。

输入示例:3 2

输出示例:3

提示:

当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。

此时你有三种方法可以爬到楼顶。

  • 1 阶 + 1 阶 + 1 阶段
  • 1 阶 + 2 阶
  • 2 阶 + 1 阶

思路

完全背包做法 ,将 不同的爬阶数 视为 重量不同的物品物品

转化为 求装满 容量为 n 的背包的方法数目, 同时 由于是爬楼梯的方法, 因此存在顺序关系, 是求排列数, 先遍历背包, 再遍历物品

代码

import java.util.*;
class Main{
    public static void main(String [] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        //dp[n] 代表 爬到n 阶的所有方法
        int [] dp = new int [n+1];
        int [] nums = new int [m];
        for(int i=0; i<m; i++){
            nums[i] = i+1;
        }
        //初始化
        dp[0] = 1;
        //先遍历背包
        for(int j = 0; j<=n; j++){
            //再遍历物品
            for(int i = 0; i < m; i++){
                if(j - nums[i] >= 0){
                    dp[j] += dp[j - nums[i]];
                }
            }
        }
        System.out.println(dp[n]);
        
    }
}

322. 零钱兑换 

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

思路

dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

        子问题为 dp[ j - coins[ i ]]

递推公式 dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

初始化: dp[ 0 ] = 0, 其余为Integer.Max 为了初始值不影响dp递推

遍历顺序: 本题求个数, 那么就无所谓顺序, 求组合数 排列数均可, 也就是先物品再背包 / 先背包再物品均可

举例推导:

代码

注意仅当dp[j-coins[i]]不是初始最大值时,该位才有选择的必要;

class Solution {
    public int coinChange(int[] coins, int amount) {
        //dp[n]表示凑成总金额所需的最少硬币个数
        //dp[j] = min(dp[j], dp[j - coins[i]] + 1);
        //初始化 dp[0] = 0 else = Integer.MIN
        int [] dp = new int [amount + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;

        for(int i = 0; i < coins.length; i++){
            for(int j = coins[i]; j <=amount; j++){
                //只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要
                if(dp[j - coins[i]] != Integer.MAX_VALUE){
                    dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
    }
}

279.完全平方数 

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

思路

与上一题 322.的区别在于 需要自己确定物品(可选用的完全平方数), 其余一样

代码

	public int numSquares(int n) {
		//dp[i] 表示和为 i 的完全平方数的最少数量 。
		int max_num = n;
		for (int i = max_num; i >= 1; i--) {
			if (judge(i)) {
				//此时 max_num 为 最接近 n 的完全平方数
				max_num = i;
				break;
			}
		}
		if (max_num == n) return 1;

		int num = (int) Math.sqrt(max_num);
		int[] nums = new int[num];
		for (int i = 0; i < num; i++) {
            nums[i] = (i+1)*(i+1);
		}

		int[] dp = new int[n + 1];
		Arrays.fill(dp, Integer.MAX_VALUE);
		dp[0] = 0;
		for(int i = 0; i<num; i++){
			for(int j = nums[i]; j<=n; j++){
//				if(dp[j - nums[i]] != Integer.MAX_VALUE){
					dp[j] = Math.min(dp[j], dp[j - nums[i]] + 1);
//				}
				//不需要這個if statement,因爲在完全平方數這一題不會有"湊不成"的狀況發生
				// ( 一定可以用"1"來組成任何一個n),故comment掉這個if statement。
			}
		}
		return dp[n];

	}

	public boolean judge(int n) {
		for (int i = 1; i < Math.sqrt(n) + 1; i++) {
			if (i * i == n) return true;
		}
		return false;
	}
}

题解代码:

区别在于对物品的定义, 其实本质是一样的 耗时也类似

class Solution {
    // 版本一,先遍历物品, 再遍历背包
    public int numSquares(int n) {
        int max = Integer.MAX_VALUE;
        int[] dp = new int[n + 1];
        //初始化
        Arrays.fill(dp, Integer.MAX_VALUE);
	
        //当和为0时,组合的个数为0
        dp[0] = 0;
        // 遍历物品
        for (int i = 1; i * i <= n; i++) {
            // 遍历背包
            for (int j = i * i; j <= n; j++) {
                //if (dp[j - i * i] != max) {
                    dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
                //}
		//不需要這個if statement,因爲在完全平方數這一題不會有"湊不成"的狀況發生( 一定可以用"1"來組成任何一個n),故comment掉這個if statement。
            }
        }
        return dp[n];
    }
}

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值