我正在研究Leetcode322:硬币兑换。
您将获得一个整数数组,表示不同面额的硬币,以及一个整数金额,表示总金额。
返回您需要的最少数量的硬币,以弥补该金额。如果这些硬币的任何组合都无法弥补这一数额,则返回-1。
你可以假设每种硬币的数量是无限的。
例子:
输入:硬币=[1,2,5],金额=11
输出: 3
说明:11 = 5 5 1
我选择自上而下的方法,在每次迭代中,我选择一个面额不大于剩余金额的硬币。听起来很容易,对吧?
以下代码通过所有测试用例。
import sys
import functools
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
@functools.cache
def _loop(remaining: int) -> int:
if remaining == 0:
return 0
y = sys.maxsize
for coin in filter(lambda x: x <= remaining, coins):
y = min(y, _loop(remaining - coin))
return (y + 1) if y < sys.maxsize else y
num_coins = _loop(amount)
return num_coins if num_coins < sys.maxsize else -1
但这一个没有。
import sys
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
num_coins = self._loop(coins, amount, 0, {})
return num_coins if num_coins < sys.maxsize else -1
def _loop(self, coins: Sequence[int], remaining: int, count: int, memo: MutableMapping[int, int]) -> int:
if remaining == 0:
return count
if remaining not in memo:
y = sys.maxsize
for coin in filter(lambda x: x <= remaining, coins):
y = min(y, self._loop(coins, remaining - coin, count + 1, memo))
memo[remaining] = y
return memo[remaining]
这两种解决方案的唯一区别是,在前者中,1
被添加到for
循环之后的结果中(因为使用了一枚硬币),在后者中,1
被添加到递归调用的参数。
第二个解决方案中我没有看到的错误是什么?
这里的操作:为了记录在案,这是修复泰哈斯·纳拉扬指出的错误后的工作代码。
import sys
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
num_coins = self._loop(coins, amount, 0, {})
return num_coins if num_coins < sys.maxsize else -1
def _loop(self, coins: Sequence[int], remaining: int, count: int, memo: MutableMapping[int, int]) -> int:
if remaining == 0:
return count
if remaining not in memo:
y = sys.maxsize
for coin in filter(lambda x: x <= remaining, coins):
y = min(y, self._loop(coins, remaining - coin, 1, memo))
memo[remaining] = (y + count) if y < sys.maxsize else y
return memo[remaining]
对于每个递归调用,修复被重置为count
到1
。
根据您使用memo
的方式,memo[x]
意味着包含总计x
美分所需的最小硬币数量。然而,事实并非如此。
让我们看看递归堆栈:
remaining = 4, count = 0, y = maxsize, take coin 1:
remaining = 3, count = 1, y = maxsize, take coin 1:
remaining = 2, count = 2, y = maxsize, take coin 1:
remaining = 1, count = 3, y = maxsize, take coin 1:
remaining = 0, count = 4, RETURN 4
y = 4, memo[1] = 4, RETURN 4
remaining = 2, count = 2, y = 4, take coin 2:
remaining = 0, count = 3, RETURN 3
y = 3, memo[2] = 3, RETURN 3
remaining = 3, count = 1, y = 3, take coin 2:
remaining = 1, count = 2, memo[1] exists, RETURN 4
y = 3, memo[3] = 3, RETURN 3
remaining = 4, count = 0, y = 3, take coin 2:
remaining = 2, count = 1, memo[2] exists, RETURN 3
y = 3, memo[4] = 3, RETURN 3
看到问题了吗<代码>备忘录中的值不正确<代码>备忘录[1]应为1,但代码将其设置为4。类似地,memo[3]
应该是2,但代码将其设置为3。
要像您正在使用的那样使用memo
数组,从下到上工作会容易得多:从一个基本条件(memo[0]=0
)开始,计算memo[1]、memo[2]、。。。备注[金额]
基于先前计算的值。
我现在正在研究leetcode322。换硬币,问题如下: 您将获得一个整数数组,表示不同面额的硬币,以及一个整数金额,表示总金额。 返回您需要的最少数量的硬币,以弥补该金额。如果这些硬币的任何组合都无法弥补这一数额,则返回-1。 你可以假设每种硬币的数量是无限的。 例1: 输入:硬币=[1,2,5],数量=11输出:3说明:11=5 1 例2: 输入:硬币=[2],金额=3输出:-1 例3: 输入
我目前正在研究leetcode上的硬币兑换动态规划问题--https://leetcode.com/problems/coin-change/. 下面是问题陈述: 我试图实现一种自上而下的记忆方法,在这种方法中,我保留了一个长度数量的数组,其中每个索引表示我可以用来生成该数量的最小硬币数量。 以下是我的Java代码: 我认为这是解决这个问题的正确的动态编程方法,但是我在leetcode上超过了时间
我在理解动态规划中的硬币兑换问题时遇到了一个小问题。简单地说,我必须用最少数量的硬币来兑换一笔钱。 我有n种面值为1=v1的硬币
以人民币的硬币为例,假设硬币数量足够多。要求将一定数额的钱兑换成硬币。要求兑换硬币数量最少。 思路说明: 这是用贪婪算法的典型应用。在本例中用python来实现,主要思想是将货币金额除以某硬币单位,然后去整数,即为该硬币的个数;余数则做为向下循环计算的货币金额。 这个算法的问题在于,得出来的结果不一定是最有结果。比如,硬币单位是[1,4,6],如果将8兑换成硬币,按照硬币数量最少原则,应该兑换成为
这是hackerrank(https://www.hackerrank.com/challenges/coin-change)的硬币更换问题。它要求计算使用给定面值的硬币对N进行更改的方法总数。 例如,有四种方法可以使用面额为1、2和3的硬币兑换4。它们是-
我试图使用贪婪算法来计算在JavaScript中达到一定数量所需的最低硬币数量 返回结果将是一个数组,由每个级别的硬币数量组成 我决定做一个函数来解决这个问题,但它不起作用 calculateChange函数包含两个参数:硬币值数组和金额。 第一步是初始化一个sum变量,该变量显示已调度的更改量。我还将创建一个数组变量,该变量将保存某个硬币的分配次数。 为此,我将迭代coins数组并将所有值设置为