[算法练习及思路-程序员面试金典(Java解法)]No51.硬币(完全背包问题+优化空间)

题号:no51

题目名:硬币
原题URL:https://leetcode-cn.com/problems/coin-lcci/
题目描述

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

示例

示例 1:

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

示例 2:

 输入: 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

限制
  • 注意:

    你可以假设:

    • 0 <= n (总金额) <= 1000000
思路

1.经典完全背包问题,容量固定,物品无限放

2.因为硬币可以无限放,所以以硬币做外层循环,避免重复

3.状态转移方程就是dp[ i ] [ j ] = (dp[ i - 1 ] [ j ] + dp [i] [j - coins[i-1]]),当如果可以用该硬币

如果不用该硬币,那就是上一个硬币的方法数就行dp[ i ] [ j ] = dp[ i - 1 ] [ j ]

4.可以将二维完全背包变成一维

解题代码
class Solution {
    public int waysToChange(int n) {
        //1000000007
        //硬币类型为25,10,5,1四种类型,总共是n元
        //当总值等于n的时候,其实一共有四种方法能达到
        //1.前面的硬币总值为n-25,最后一个硬币为25元
        //2.前面的硬币总值为n-10,最后一个硬币为10元
        //3.前面的硬币总值为n-5,最后一个硬币为5元
        //4.前面的硬币总值为n-1,最后一个硬币为1元
        //完全背包问题
        int mod = 1000000007;
        int[] coins = {1,5,10,25};
        int[][] dp = new int[coins.length+1][n+1];
        //先初始化所有硬币的取出方式都为1
        for (int i = 0; i < dp.length; i++) {
            dp[i][0] = 1;
        }

        for (int i = 1; i <= coins.length; i++) {
            for (int j = 1; j < n + 1; j++) {
                //遍历硬币
                dp[i][j] = dp[i - 1][j];
                if (j - coins[i-1] >= 0) dp[i][j] = (dp[i - 1][j] + dp[i][j - coins[i-1]])%mod;
            }
        }
        return dp[coins.length][n];
    }
}
优化

1.优化思路就是讲二维变成一维,要去掉的维度要对原来没有影响

2.也就是说,可以作为滚动数组来操作

3.观察二维,可以看到状态方程式都是(i,j)和(i-1,j)在挂钩,其实用前面一维做滚动就够用了

class Solution {
    public int waysToChange(int n) {
        //完全背包问题
        int mod = 1000000007;
        int[] coins = {1,5,10,25};
        int[][] dp = new int[coins.length+1][n+1];
        //先初始化所有硬币的取出方式都为1
		dp[0] = 1;

        for (int i = 1; i <= coins.length; i++) {
            for (int j = 1; j < n + 1; j++) {
                //遍历硬币
                if (j - coins[i-1] >= 0) dp[j] = (dp[j] + dp[j - coins[i-1]])%mod;
            }
        }
        return dp[coins.length][n];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值