微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

计算给定 Haskell 变化量的最小硬币数量

如何解决计算给定 Haskell 变化量的最小硬币数量

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

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

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

例如:

Input  : coinChange 34 [1,5,10,25,50,100]
Output : [4,1,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,20,100]
[64,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,100]

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

(64 `quot` 100):(coinChange' (64 `rem` 100) [1,50])
0:((64`quot`50):coinChange' (64`rem`50) [1,20])
0:(1:coinChange' 14 [1,20])
0:(1:((14`quot` 20):coinChange' (14 `rem` 20) [1,10]))
0:(1:(0:coinChange 14 [1,10]))
0:(1:(0:((14`quot` 10) : coinChange' (14 `rem` 10) [1,5])))
0:(1:(0:( 1 : coinChange' (14 `rem` 10) [1,5])))
0:(1:(0:( 1 : coinChange' 4 [1,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,0]
final output: [0,0]

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

coinChange 64 [1,100]
[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,0]

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

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

coinChange 0 ds = 取(长度 ds)(重复 0) coinChange c ds = let (x:xs) = 反向 ds 反过来( (c quot x): coinChange' (c rem x) xs )

coinChange' 0 ds = take (length ds)(重复 0) coinChange' c ds = let (x:xs) = 反向 ds in (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 的这个错误

解决方法

在这个答案中,我将重点关注你的这个尝试:

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

我认为问题确实出在 where (x:xs) = reverse ds 函数中的 coinChange' 部分。每次递归调用都会反转面额列表。因此,您从该 xs 子句中的模式匹配中获得的 where 是没有最大面额的面额的反向列表。但该列表仍然是反向的,因此您不应再次将其作为参数传递给 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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。