【问题标题】:Calculate the Minimum Number of Coins For Given Amount of Change in Haskell在 Haskell 中计算给定变化量的最小硬币数量
【发布时间】:2021-06-17 09:07:39
【问题描述】:

我正在尝试为Change-making problem 编写算法。

我假设硬币系统是规范的,这意味着总是选择小于剩余数量的最大硬币的贪心算法是最优算法。

coinChange 是算法的函数。输入是给定硬币系统的金额和面额。该函数输出每种面额所需的最小硬币数量。

例如:

Input  : coinChange 34 [1, 5, 10, 25, 50, 100]
Output : [4,1,0,1,0,0]

coinChange 的类型声明是:

coinChange :: Integer -> [Integer] -> [Integer]

我找到了这个解决方案,我明白它为什么有效:

coinChange 0 ds = take (length ds) (repeat 0)
coinChange c ds = (coinChange (c `rem` d) (init ds) ) ++ [c `quot` d] 
                   where d = last ds

但是,当我尝试制定自己的解决方案时,我收到了几条错误消息。

一开始,我试过了:

coinChange c [] = []
coinChange c ds = reverse ( (c `quot` x): coinChange (c `rem` x) xs )
                 where (x:xs) = reverse ds

我尝试颠倒硬币面额的顺序,所以我从最大的第一个开始。我认为这比使用lastinit 更方便。

当我运行它时,我得到:

coinChange 64 [1,2,5,10,20,50,100]
[64,0,0,0,0,0,0]

我在这里得到 64 似乎很奇怪。

如果我使用递归函数,我认为在整个列表上使用reverse 会造成混淆,因为列表的某些部分会被多次反转。所以我尝试了这个:

coinChange c [] = []
coinChange c ds =reverse( (c `quot` x):(coinChange' (c `rem` x) xs ))
                where (x:xs) = (reverse ds)

coinChange' c [] = []
coinChange' c ds = (c`quot`x):(coinChange' (c `rem` x) xs )
                where (x:xs) = reverse ds

如果我尝试:

coinChange 64 [1,2,5,10,20,50,100]

我以为我会得到[0,2,0,1,0,1,0] 作为我的最终输出:

(64 `quot` 100):(coinChange' (64 `rem` 100) [1,2,5,10,20,50])
0:((64`quot`50):coinChange' (64`rem`50) [1,2,5,10,20])
0:(1:coinChange' 14 [1,2,5,10,20])
0:(1:((14`quot` 20):coinChange' (14 `rem` 20) [1,2,5,10]))
0:(1:(0:coinChange 14 [1,2,5,10]))
0:(1:(0:((14`quot` 10) : coinChange' (14 `rem` 10) [1,2,5])))
0:(1:(0:( 1 : coinChange' (14 `rem` 10) [1,2,5])))
0:(1:(0:( 1 : coinChange' 4 [1,2,5])))
0:(1:(0:( 1 : ((4 `quot` 5):coinChange' (4`rem` 5) [1,2]))))
0:(1:(0:( 1 : (0:coinChange' 4 [1,2]))))
0:(1:(0:( 1 : (0:((4`quot`2):coinChange (4`rem`2) [1])))))
0:(1:(0:( 1 : (0:(2:coinChange 0 [1])))))
0:(1:(0:( 1 : (0:(2:((0`quot`1):coinChange' (0`rem` 1) []))))))
0:(1:(0:( 1 : (0:(2:(0:coinChange' 0 []))))))
0:(1:(0:( 1 : (0:(2:(0:[]))))))
reverse [0,1,0,1,0,2,0]
final output: [0,2,0,1,0,1,0]

但是,当我在终端中运行此代码时,我得到:

coinChange 64 [1,2,5,10,20,50,100]
[0,0,0,0,0,64,0]

为什么我的方法不起作用?

然后我尝试了:

coinChange 0 ds = take (length ds) (repeat 0)
coinChange c ds =  reverse( (c `quot` x): coinChange' (c `rem` x) xs )
                   where (x:xs) = reverse ds

coinChange' 0 ds = take (length ds) (repeat 0)
coinChange' c ds =  (c `quot` x): coinChange' (c `rem` x) xs 
                   where (x:xs) = reverse ds

我从已经运行的解决方案中选择了coinChange 0 ds = take (length ds) (repeat 0)

但是,当我在终端中运行这段代码时,我得到了同样的错误:

coinChange 64 [1,2,5,10,20,50,100]
[0,0,0,0,0,64,0]

我认为主要问题在于where (x:xs) = reverse ds。为什么这部分代码没有按我预期的方式工作?

当我使用 let 而不是 where 时,我仍然遇到同样的错误。

coinChange 0 ds = take (length ds) (repeat 0) coinChange c ds = let (x:xs) = reverse ds 反向((cquotx):coinChange'(cremx)xs)

coinChange' 0 ds = take (length ds) (repeat 0) coinChange' c ds = let (x:xs) = 反向 ds 在 (c quot x): coinChange' (c rem x) xs

我认为问题可能在于我使用的是(x:xs)

所以,我尝试了:

coinChange 0 ds = take (length ds) (repeat 0)
coinChange c ds =  let xs = reverse ds
                    in reverse( (c `quot` (head xs)): coinChange' (c `rem` (head xs)) (tail xs) )


coinChange' 0 ds = take (length ds) (repeat 0)
coinChange' c ds =  let xs = reverse ds
                    in (c `quot` (head xs)): coinChange' (c `rem` (head xs)) (tail xs) 

这仍然给出了同样的错误。

我尝试使用连接运算符(++),而不是前置运算符:,看看是否有帮助:

coinChange 0 ds = take (length ds) (repeat 0)
coinChange c ds =  let xs = reverse ds
                    in coinChange (c `rem` (head xs)) (tail xs) ++ [c `quot` (head xs)]

这段代码我仍然遇到同样的错误。

看来问题一定出在我颠倒硬币面额列表的方法上。

为什么我所有的尝试都失败了?当商应该是 1 时,为什么我一直收到 64 的此错误?

【问题讨论】:

  • 感谢您的努力,但您能否将其作为针对一个特定问题的一个集中问题?不需要整个历史,只需代码、输入、所需输出、实际输出/错误、问题。 :)

标签: haskell recursion modular-arithmetic coin-change


【解决方案1】:

在这个答案中,我将重点介绍您的这种尝试:

coinChange c [] = []
coinChange c ds =reverse( (c `quot` x):(coinChange' (c `rem` x) xs ))
                where (x:xs) = (reverse ds)

coinChange' c [] = []
coinChange' c ds = (c`quot`x):(coinChange' (c `rem` x) xs )
                where (x:xs) = reverse ds

我认为问题确实出在coinChange' 函数中的where (x:xs) = reverse ds 部分。每个递归调用都会反转面额列表。所以xs 你从where 子句中的模式匹配中得到的xs 是没有最大面额的面额列表。但是该列表仍然是相反的,因此您不应再次将其作为参数传递给coinChangecoinChange' 函数。您可以在将其传递给递归调用之前再次反转此列表,但这不是很有效。我建议只在coinChange 函数中颠倒面额。

另外,coinChange 函数可以简化,因为它基本上只需要反转面额和结果列表。

这就是它的样子:

coinChange c ds = reverse (coinChange' c (reverse ds))

coinChange' c [] = []
coinChange' c (x:xs) = (c `quot` x) : coinChange' (c `rem` x) xs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多