换零钱问题迭代解法

搬运自 http://blog.sina.com.cn/s/blog_7daf3d040101od8p.html

问题来源 SICP

线性递归和迭代(尾递归)
计算机程序的构造与解释(SICP)递归与迭代

计算机程序的构造与解释(SICP)递归与迭代


树形递归(优化尽量先从瓶颈优化,尽量先从算法优化)
指数级 线性

计算机程序的构造与解释(SICP)递归与迭代

这个结果不能说树形递归是无用的,对于层级数据结构而不是数,就会发现树形递归是很自然并强大的工具。即使对与数的计算,它也可能帮助我们理解和设计程序,更加的直观。

实例:对于1美元,给定1/2美元、1/4美元、10美分、5美分、1美分,将1美元换成零钱,有多少种方式?更一般的问题是,对于任意数量的现金,有多少种换零钱的方式?

对于现金a,硬币种类数目n,换零钱的方式数目等于:
  • 用除了第一种硬币之外的硬币换的数目,加上
  • 把现金a-d用n种硬币换的数目,d为第一种硬币的面额
这样逐步缩小问题的规模,但应有下列规则:
  • 当a=0,返回换零钱方式数目为1
  • 当a<0,返回换零钱方式数目为0
  • 当n=0,返回换零钱方式数目为0
转换为代码:
( define (count-change  amount)
  (cc  amount  5))
( define (cc  amount  kinds-of-coins)
  ( cond ((=  amount  0 1)
           (( or (<  amount  0) (=  kinds-of-coins  0))  0)
           ( else (+  (cc  amount
                              (-  kinds-of-coins  1))
                        (cc  (-  amount
                                   (first-denomination  kinds-of-coins))
                               kinds-of-coins)))))
( define (first-denomination  kinds-of-coins)
  ( cond ((=  kinds-of-coins  1 1)
           ((=  kinds-of-coins  2 5)
           ((=  kinds-of-coins  3 10)
           ((=  kinds-of-coins  4 25)
           ((=  kinds-of-coins  5 50)))

树形递归会有很多冗余计算,但也同样直观,易于理解。如果要想一个其他的更好的算法,就不那么容易了。对于冗余,可以把计算过的过程保存下来,下次再计算时查看是否计算过,避免重复计算。

临时想了一个迭代的算法,结果很不直观啊
计算机程序的构造与解释(SICP)递归与迭代

//
博主的评论:
第二个方法相当于先用1分填满;然后清空加进去一个5分,再执行同样的操作,直至5分这个位置也被填满;接着扔进去一个10分.... 以此一直到50分也被填满。同时巧妙地用sum记录总数
另外, ((> temp amount) (cc-iter-1 n1 n2 n3 n4 n5 amount sum))) 很漂亮,比如说如果是1001分,20个50分和1个1分恰好覆盖,这时再多一个50分就超出总数了,于是次数再跳回cc-iter-1,n2到n5都为0,直接print sum。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
零钱找零问题是一个经典的动态规划问题,也可以使用贪心算法来解决。下面给出两种解法的代码实现。 1. 动态规划解法: ```objc #import <Foundation/Foundation.h> NSInteger minCoins(NSArray<NSNumber *> *coins, NSInteger amount) { NSMutableArray<NSNumber *> *dp = [NSMutableArray arrayWithCapacity:amount + 1]; for (NSInteger i = 0; i <= amount; i++) { dp[i] = @(amount + 1); } dp[0] = @0; for (NSInteger i = 1; i <= amount; i++) { for (NSNumber *coin in coins) { if (i >= coin.integerValue) { dp[i] = @(MIN(dp[i].integerValue, dp[i - coin.integerValue].integerValue + 1)); } } } return dp[amount].integerValue > amount ? -1 : dp[amount].integerValue; } int main(int argc, const char * argv[]) { @autoreleasepool { NSArray<NSNumber *> *coins = @[@1, @2, @5]; NSInteger amount = 11; NSInteger result = minCoins(coins, amount); NSLog(@"The fewest number of coins needed to make change for %ld is: %ld", amount, result); } return 0; } ``` 在上述代码中,我们定义了一个名为 `minCoins` 的函数来计算零钱找零问题的最少硬币数量。使用动态规划的思想,我们创建了一个数组 `dp`,其中 `dp[i]` 表示凑够金额 `i` 的最少硬币数量。通过迭代计算每个金额的最少硬币数量,最终得到凑够金额 `amount` 的最少硬币数量。 在 `main` 函数中,我们设定了硬币面额数组 `coins` 为 `[1, 2, 5]`,目标金额 `amount` 为 `11`,并调用 `minCoins` 函数来计算最少硬币数量。最后,使用 `NSLog` 打印出结果。 编译运行上述代码,将会输出:The fewest number of coins needed to make change for 11 is: 3,表示凑够金额 `11` 需要的最少硬币数量为 `3`。 2. 贪心算法解法: ```objc #import <Foundation/Foundation.h> NSInteger minCoins(NSArray<NSNumber *> *coins, NSInteger amount) { NSInteger count = 0; for (NSInteger i = coins.count - 1; i >= 0 && amount > 0; i--) { if (coins[i].integerValue <= amount) { NSInteger num = amount / coins[i].integerValue; count += num; amount -= num * coins[i].integerValue; } } return amount == 0 ? count : -1; } int main(int argc, const char * argv[]) { @autoreleasepool { NSArray<NSNumber *> *coins = @[@1, @2, @5]; NSInteger amount = 11; NSInteger result = minCoins(coins, amount); NSLog(@"The fewest number of coins needed to make change for %ld is: %ld", amount, result); } return 0; } ``` 在上述代码中,我们同样定义了一个名为 `minCoins` 的函数来计算零钱找零问题的最少硬币数量。使用贪心算法的思想,我们从最大面额的硬币开始,尽可能多地使用该面额的硬币,然后逐步减小面额直到凑够目标金额。 在 `main` 函数中,我们同样设定了硬币面额数组 `coins` 为 `[1, 2, 5]`,目标金额 `amount` 为 `11`,并调用 `minCoins` 函数来计算最少硬币数量。最后,使用 `NSLog` 打印出结果。 编译运行上述代码,将会输出:The fewest number of coins needed to make change for 11 is: 3,表示凑够金额 `11` 需要的最少硬币数量为 `3`。 希望以上示例代码对你有所帮助。如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值