力扣 322.零钱兑换(动态规划问题)

力扣 322.零钱兑换(动态规划问题)

题目
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
动态规划问题解题一般分为
1、明确问题
2、转移方程
3、初始条件和边界情况
4、计算顺序
我们按照这个步骤来对这道算法题进行解答

一、明确问题(简化定义)

题目说的是用最少多少硬币拼出amount(就是11),那么明确最优策略下,最后一枚硬币只可能是coin[i](i为coin数组下标){就是1和2和5},意思就是拼出最优解的最后一枚硬币一定是三种硬币中的一种,
那么因为是最优策略,所以必须让amount-coin[i](11-coin[i])最少。
那么问题就转化成了另一个问题
最少用多少枚硬币可以拼出11-coin[i]
简化定义:
设状态f(x)=最少用多少枚硬币可以拼出x

  • 如果coin[i]为1,那么f(11)=f(11-1)+1(最后加1是最后一枚硬币)
  • 如果coin[i]为2,那么f(11)=f(11-2)+1
  • 如果coin[i]为5,那么f(11)=f(11-5)+1

那么此时问题转换成了使得组成最后一枚硬币前面的硬币数量最少

二、转移方程

由上面可知现在问题转化成了
f(11)=min { f(11-1)+1,f(11-2)+1,f(11-5)+1}
f(11)为拼出11所需最少硬币数
f(11-1)为拼出10所需最少硬币数。。。

三、初始条件和边界情况

两个问题::x-1,x-2,x-5小于0怎么办?什么时候使递归停下来?
如果不能拼出x,就定义f(x)=无穷,例如f(-1),f(-2)=无穷
所以f(1)=min{f(0)+1,f(-1)+1,f(-4)+1}
初始条件:f(0)=0
初始条件是转移方程算不出来的,只能通过自己定义,所以说边界条件很重要。

四、计算顺序

α为无穷

f(0)f(1)f(2)f(3)f(4)f(5)f(6)f(7)f(8)
αα012223233

这些都可以通过以下公式一步一步算出来,并且我们在算f(n)的时候f(n)前面的都已经算出来了
f(11)=min { f(11-1)+1,f(11-2)+1,f(11-5)+1}

上面就是全部的求解过程

以下是java代码

package test;

import java.util.Scanner;

/**
 * @author zhazhalin
 * @version 1.0
 * @date 2021/4/6 21:05
 */

/**
 * 257三枚硬币拼出27,问有多少种拼法
 */
public class Coin {
    public static void main(String[] args) {
        int[] a = {2, 5, 7};
        int f = f(a, 27);
        System.out.println(f);
    }

    public static int f(int[] a, int sum) {
        //首先定义边界值
        int[] f = new int[sum + 1];
        int n = a.length;
        f[0] = 0; //定义边界条件
        for (int i = 1; i <= sum; ++i) {
            f[i] = Integer.MAX_VALUE;  //将数组中的数定义为无穷大
            for (int j = 0; j < n; ++j) {
                //i>a[j]要满足i-a[j]必须有足够的钱才能继续向前推导,此处的a[j]就是对应的257三种硬币
                if (i >= a[j] && f[i - a[j]] != Integer.MAX_VALUE) { //并且必须确保
                    //当我们计算到f[sum]的时候,前面的数值都已经计算过了,这就是动态规划的记忆性
                    f[i] = Math.min(f[i - a[j]] + 1, f[i]);
                }
            }
        }
        if (f[sum]==Integer.MAX_VALUE){
            return -1;
        }
        return f[sum];
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值