Leetcode 面试题08.11:硬币(动态规划)

本文详细解析了一道经典的动态规划问题——使用不同面值的硬币组合成特定金额的方法数。通过二维和一维数组的动态规划算法实现,探讨了状态转移方程,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

示例

输入: n = 10
输出:4
解释: 有四种方式可以凑成总金额:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1

思路

这一题很容易想到要动态规划,然后……我就觉得很难了,sigh
用一个二维数组 dp[i][j] 来存是用第i种硬币组合成j金额的方法种数

i取0-3,分别代表1,5,10,25
如dp[3][27]=dp[2][27]+dp[3][2]:
dp[3][27]:代表用面值25,10,5,1的硬币组成27金额的可能
dp[2][27]:代表不用面值25只用1,5,10组成27的可能
dp[3][2]:代表用了一个面值25,剩下金额2用1,5,10,25组成的可能
那么要加个判断就是j-conis[i]的金额要大于0,不然就代表第i种币值不能用,如上面例子
dp[3][2]由于2<25,2<10,2<5,所以会一直将dp[i][2]=dp[i-1][2]来保证继续直到dp[0][2],只用面值1组成,那么就只有1种情况了。
参考

针对某种硬币,有两种可能性:
(1)不用这种硬币:dp[ i - 1 ][ j ]
(2)用这种硬币:dp[ i ][ j - coins[ i ] ]
结果应为两种情况之和。
状态转移方程为:dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[ i ][ j - coins[ i ] ]

代码如下

二维数组

class Solution {
    public int waysToChange(int n) {
        int[][] dp = new int[4][n+1];
        int[] coins = {1,5,10,25};
        for(int j=0;j<=n;j++){
            //i=0,表示只用第一种硬币(1分),此时只有一种方法
            dp[0][j] = 1;
        }
        for(int i=1;i<4;i++){
            //j=0,表示0分有几种方法,只有一种,那就是一个硬币都不用
            dp[i][0] = 1;
        }
        for(int i=1;i<4;i++){
            for(int j=1;j<=n;j++){
                if(j<coins[i]){
                	//j小于当前这种硬币的面值时,只能不选择
                    dp[i][j] = dp[i-1][j];
                }else{
                	//选择当前这种硬币+不选择当前这种硬币
                    dp[i][j] = (dp[i][j-coins[i]]+dp[i-1][j])%1000000007;
                }
            }
        }
        return dp[3][n];
    }
}

一维数组

其实是二维数组的简化,可以对比着理解

class Solution {
    public int waysToChange(int n) {
        int[] dp = new int[n+1];
        int[] coins = {1,5,10,25};
        Arrays.fill(dp,1);
        //从i=1开始
        for(int i=1;i<4;i++){
            for(int j=1;j<=n;j++){
            	//j小于coins[i]的时候,不能选择当前这种硬币,方法数不会增加
                if(j>=coins[i]){
                	//j大于等于coins[i时,方法数会增加“选择当前这种硬币”的情况
                    dp[j] = (dp[j-coins[i]]+dp[j])%1000000007;
                }
            }
        }
        return dp[n];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值