首页 > 其他分享 >零钱兑换

零钱兑换

时间:2022-11-25 18:25:21浏览次数:51  
标签:硬币 int memo coins 零钱 amount 兑换 dp

零钱兑换

[传送门]( 322. 零钱兑换 - 力扣(LeetCode) )

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

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

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

1、确定 base case

if (amount < 0)
			return -1; //amount<0的话,返回-1
if (amount == 0)  
			return 0;  //amount为0的话,直接返回0

2、确定「状态」,也就是原问题和子问题中会变化的变量

由于硬币数量无限,硬币的面额也是题目给定的,只有目标金额会不断地向 base case 靠近,所以唯一的「状态」就是目标金额 amount

3、确定「选择」,也就是导致「状态」产生变化的行为

你在选择硬币,你每选择一枚硬币,就相当于减少了目标金额。所以说所有硬币的面值,就是你的「选择」

4、明确 dp 函数/数组的定义

有一个递归的 dp 函数,一般来说函数的参数就是状态转移中会变化的量,也就是上面说到的「状态」;函数的返回值就是题目要求我们计算的量。就本题来说,状态只有一个,即「目标金额」,题目要求我们计算凑出目标金额所需的最少硬币数量。

dp 函数:dp(n) 表示,输入一个目标金额 n,返回凑出目标金额 n 所需的最少硬币数量

带备忘录的递归

递归方程:

\[dp(n)=\begin{cases} 0,n=0\\ -1,n<0 \\min\{dp(n-coin)+1|coin \in coins\} ,n>0\\\end{cases} \]

class Solution {
   int[] memo;

	public int coinChange(int[] coins, int amount) {
		memo = new int[amount + 1];
		Arrays.fill(memo, -2);//填入一个memo不可能取到的值
		return dp(coins, amount);
	}

//表示凑出n金额最少需要dp(coins,n)个硬币
	public int dp(int[] coins, int amount) {
		// base case
		if (amount < 0)
			return -1;
		if (amount == 0)
			return 0;
		if (memo[amount] != -2)  //先判断备忘录中有没有值,有的话直接返回
			return memo[amount];
		int res = Integer.MAX_VALUE;  
		for (int coin : coins) {
			int subProblem = dp(coins, amount-coin);
			if(subProblem==-1) continue;
			res = Math.min(res, subProblem+1);
		}
		memo[amount] = (res==Integer.MAX_VALUE)?-1:res;
		return memo[amount];
	}
}

dp 数组的迭代解法

dp 数组的定义:当目标金额为 i 时,至少需要 dp[i] 枚硬币凑出

public int coinChange(int[] coins, int amount) {
		//当目标金额为i时,至少需要 dp[i] 枚硬币凑出。
		int[] dp = new int[amount+1];
		Arrays.fill(dp, amount+1);
		//base case
		dp[0]=0;
		//外层循环遍历,金额为i时,需要的最少硬币数
		for(int i=1;i<=amount;i++) {
			//遍历每一个硬币
			for(int coin:coins) {
				if (i - coin < 0) {
	                continue;
	            }
				//不取硬币或取硬币
				dp[i]=Math.min(dp[i], dp[i-coin]+1);
			}
		}
		return (dp[amount] == amount + 1) ? -1 : dp[amount];
	}

标签:硬币,int,memo,coins,零钱,amount,兑换,dp
From: https://www.cnblogs.com/ANDQE/p/16925979.html

相关文章

  • #yyds干货盘点# 动态规划专题:兑换零钱
    1.简述:描述给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。如果......
  • P4027 [NOI2007] 货币兑换
    前言打完这道题,感觉对李超线段树又有了进一步的了解。分析一个明显的性质,如果要买卷或卖卷的话,那么一定是全买全卖的,显然。设\(ans_i\)为第\(i\)天拥有的最大钱数,......
  • 【中学】零钱换整钱
    小明手中有硬币,小红手中有若干张10元的纸币。已知1角硬币厚1.8mm,5角硬币厚1.5mm,1元硬币厚2.0mm。小红拿出若干张10元的纸币,小明要将1角的硬币放成一摞,将5角......
  • 322. 零钱兑换 ---- 动态规划
    给你一个整数数组coins,表示不同面额的硬币;以及一个整数amount,表示总金额。计算并返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,......
  • 代码随想录day45 | 70. 爬楼梯 322. 零钱兑换 279. 完全平方数
    70.爬楼梯题目|文章思路这道题目要求有序,因此是全背包的排列做法。1.数组下标以及含义dp[i]:爬到n台阶一共有dp[i]种方法。2.递推关系dp[i]+=dp[i-j];3.初始......
  • 代码随想录day44 | 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ
    完全背包文章思路有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物......
  • 动态规划-零钱兑换
    零钱兑换也是动态规划的典型问题,一般是给你几种零钱,数量不限,给一个amount,问共有多少种兑零钱的方法。我们看一个案例案例1:给你一个整数数组coins,表示不同面额的硬币;以......
  • PHP对接微信支付,发起商家转账API,商家转账到零钱
    <?phpnamespaceapp\common\service;useapp\common\exception\BaseException;classWechatPayTransfer{protected$wxapp=[];publicfunction__construct($wxap......
  • 零钱通系统
    零钱通系统分析:1.选择菜单,用到基本的switch语句2.最好做的功能即是退出3.创建两个类,账户类和记录类,其中界面所展示的零钱通明细中的金额,时间,余额都放于账户类创建的记......
  • LC322---零钱兑换
    ​​322.零钱兑换​​难度中等1087给定不同面额的硬币​​coins​​​和一个总金额​​amount​​​。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没......