LeetCode: 零钱兑换,个人理解

今天在LeetCode上练了下零钱兑换

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

ps:可以认为每种硬币的数量是无限的

这个属于完全背包类型问题,我们可以通过动态规划,去解决该问题动态规划的定义我就不重复了. 下面我直接贴出答案

int [] coins = {3, 5};

public int coinChange(int[] coins, int amount) {
		int [] dp = new int[amount + 1];
		Arrays.fill(dp, Integer.MAX_VALUE);
		dp[0] = 0;
		// dp curr  : [0, MAX, MAX...];
		for (int currAmount = 1; currAmount <= amount; currAmount++) {
			for (int coin : coins) {
				int leftAmount = currAmount - coin;
				if (leftAmount < 0 || dp[leftAmount] == Integer.MAX_VALUE) continue;
				dp[currAmount] = Integer.min(dp[leftAmount] + 1, dp[currAmount]);
			}
		}
		return dp[amount] == Integer.MAX_VALUE ? -1: dp[amount] ;
}

自下而上找出子问题的最优解,先计算出需要总金额之前的最优解;

dp数组存储了子问题的最优解,如图,如果我们要找到11的最优解,那么我们应该从不同价值硬币分别找到最优解
在这里插入图片描述

dp[currAmount] = Integer.min(dp[leftAmount] + 1, dp[currAmount]);

  1. currAmount是当前需要求出需要最少硬币的金额(即子问题)
  2. +1 是因为 dp[leftAmount]是其他子问题的最优解,应该再加上一个硬币,才是当前要求的答案
  3. 会循环硬币面额的数组,以此找到不同子问题的最优解,找到需要最少数量硬币的答案

下面是我把执行逻辑进行了推导
在这里插入图片描述
对于红色区域无解内容,我们通过下面代码进行规避,也就是剪枝
if (leftAmount < 0 || dp[leftAmount] == Integer.MAX_VALUE) continue;

这样看可能直观感受不到,你可以想象图片反过来(Amount在最下面),这样可能会清晰一点

参考资料

Bilibili视频: Leetcode 322 零钱兑换 动态规划解法
算法小抄: 动态规划系列

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值